atlas/web/_js/draw.js
Hans5958 804159e116 Reduce copyright notice, add 2022 contributors, add missing notice
The lengthy boilerplate is unnecessary, especially since it is already linked. The type of license can stay there instead.
2022-04-09 16:33:10 +07:00

383 lines
9.3 KiB
JavaScript

/*
========================================================================
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 initDraw(){
var finishButton = document.getElementById("finishButton");
var resetButton = document.getElementById("resetButton");
var undoButton = document.getElementById("undoButton");
var redoButton = document.getElementById("redoButton");
var highlightUnchartedLabel = document.getElementById("highlightUnchartedLabel");
var objectInfoBox = document.getElementById("objectInfo");
var hintText = document.getElementById("hint");
var exportButton = document.getElementById("exportButton");
var cancelButton = document.getElementById("cancelButton");
var exportOverlay = document.getElementById("exportOverlay");
var exportCloseButton = document.getElementById("exportCloseButton");
var rShiftPressed = false;
var lShiftPressed = false;
var shiftPressed = false;
var backgroundCanvas = document.createElement("canvas");
backgroundCanvas.width = 2000;
backgroundCanvas.height = 2000;
var backgroundContext = backgroundCanvas.getContext("2d");
var highlightUncharted = true;
renderBackground();
container.style.cursor = "crosshair";
var path = [];
var drawing = true;
var undoHistory = [];
var lastPos = [0, 0];
render(path);
container.addEventListener("mousedown", function(e){
lastPos = [
e.clientX
,e.clientY
];
});
function getCanvasCoords(x, y){
x = x - container.offsetLeft;
y = y - container.offsetTop;
var pos = [
~~((x - (container.clientWidth/2 - innerContainer.clientWidth/2 + zoomOrigin[0]))/zoom)+0.5
,~~((y - (container.clientHeight/2 - innerContainer.clientHeight/2 + zoomOrigin[1]))/zoom)+0.5
];
if(shiftPressed && path.length > 0){
var previous = path[path.length-1];
if(Math.abs(pos[1] - previous[1]) > Math.abs(pos[0] - previous[0]) ){
pos[0] = previous[0];
} else {
pos[1] = previous[1];
}
}
return pos;
}
container.addEventListener("mouseup", function(e){
if(Math.abs(lastPos[0] - e.clientX) + Math.abs(lastPos[1] - e.clientY) <= 4 && drawing){
var coords = getCanvasCoords(e.clientX, e.clientY);
path.push(coords);
render(path);
undoHistory = [];
redoButton.disabled = true;
undoButton.disabled = false;
if(path.length >= 3){
finishButton.disabled = false;
}
}
});
window.addEventListener("mousemove", function(e){
if(!dragging && drawing && path.length > 0){
var coords = getCanvasCoords(e.clientX, e.clientY);
render(path.concat([coords]));
}
});
window.addEventListener("keyup", function(e){
if(e.key == "Enter"){
finish();
} else if(e.key == "z" && e.ctrlKey){
undo();
} else if(e.key == "y" && e.ctrlKey){
redo();
} else if(e.key == "Escape"){
exportOverlay.style.display = "none";
} else if (e.key === "Shift" ){
if(e.code === "ShiftRight"){
rShiftPressed = false;
} else if(e.code === "ShiftLeft"){
lShiftPressed = false;
}
shiftPressed = rShiftPressed || lShiftPressed;
}
});
window.addEventListener("keydown", function(e){
if (e.key === "Shift" ){
if(e.code === "ShiftRight"){
rShiftPressed = true;
} else if(e.code === "ShiftLeft"){
lShiftPressed = true;
}
shiftPressed = rShiftPressed || lShiftPressed;
}
});
finishButton.addEventListener("click", function(e){
finish();
});
undoButton.addEventListener("click", function(e){
undo();
});
redoButton.addEventListener("click", function(e){
redo();
});
resetButton.addEventListener("click", function(e){
reset();
});
cancelButton.addEventListener("click", function(e){
reset();
});
document.getElementById("nameField").addEventListener("keyup", function(e){
if(e.key == "Enter"){
exportJson();
}
});
document.getElementById("websiteField").addEventListener("keyup", function(e){
if(e.key == "Enter"){
exportJson();
}
});
document.getElementById("subredditField").addEventListener("keyup", function(e){
if(e.key == "Enter"){
exportJson();
}
});
exportButton.addEventListener("click", function(e){
exportJson();
});
exportCloseButton.addEventListener("click", function(e){
reset();
exportOverlay.style.display = "none";
});
exportCloseButton.addEventListener("click", function(e){
exportDirectPost();
})
document.getElementById("highlightUncharted").addEventListener("click", function(e){
highlightUncharted = this.checked;
render(path);
});
function exportJson(){
var exportObject = {
id: 0
,name: document.getElementById("nameField").value
,description: document.getElementById("descriptionField").value
,website: document.getElementById("websiteField").value
,subreddit: document.getElementById("subredditField").value
,center: calculateCenter(path)
,path: path
};
var jsonString = JSON.stringify(exportObject, null, "\t");
var textarea = document.getElementById("exportString");
jsonString = jsonString.split("\n");
jsonString = jsonString.join("\n ");
jsonString = " "+jsonString;
textarea.value = jsonString;
console.log("a");
var directPostUrl = "https://www.reddit.com/r/placeAtlas2/submit?selftext=true&title=New%20Submission&text="+encodeURIComponent(document.getElementById("exportString").value);
document.getElementById("exportDirectPost").href=directPostUrl;
exportOverlay.style.display = "flex";
textarea.focus();
textarea.select();
}
function calculateCenter(path){
var area = 0,
i,
j,
point1,
point2;
for (i = 0, j = path.length - 1; i < path.length; j=i,i++) {
point1 = path[i];
point2 = path[j];
area += point1[0] * point2[1];
area -= point1[1] * point2[0];
}
area *= 3;
var x = 0,
y = 0,
f;
for (i = 0, j = path.length - 1; i < path.length; j=i,i++) {
point1 = path[i];
point2 = path[j];
f = point1[0] * point2[1] - point2[0] * point1[1];
x += (point1[0] + point2[0]) * f;
y += (point1[1] + point2[1]) * f;
}
return [~~(x / area)+0.5, ~~(y / area)+0.5];
}
function undo(){
if(path.length > 0 && drawing){
undoHistory.push(path.pop());
redoButton.disabled = false;
if(path.length == 0){
undoButton.disabled = true;
}
render(path);
}
}
function redo(){
if(undoHistory.length > 0 && drawing){
path.push(undoHistory.pop());
undoButton.disabled = false;
if(undoHistory.length == 0){
redoButton.disabled = true;
}
render(path);
}
}
function finish(){
drawing = false;
render(path);
objectInfoBox.style.display = "block";
hintText.style.display = "none";
finishButton.style.display = "none";
undoButton.style.display = "none";
redoButton.style.display = "none";
resetButton.style.display = "none";
highlightUnchartedLabel.style.display = "none";
document.getElementById("nameField").focus();
}
function reset(){
path = [];
undoHistory = [];
finishButton.disabled = true;
undoButton.disabled = true; // Maybe make it undo the cancel action in the future
redoButton.disabled = true;
drawing = true;
render(path);
objectInfoBox.style.display = "none";
hintText.style.display = "block";
finishButton.style.display = "block";
undoButton.style.display = "block";
redoButton.style.display = "block";
resetButton.style.display = "block";
highlightUnchartedLabel.style.display = "block";
document.getElementById("nameField").value = "";
document.getElementById("descriptionField").value = "";
document.getElementById("websiteField").value = "";
document.getElementById("subredditField").value = "";
}
function renderBackground(){
backgroundContext.clearRect(0, 0, canvas.width, canvas.height);
backgroundContext.fillStyle = "rgba(0, 0, 0, 1)";
//backgroundContext.fillRect(0, 0, canvas.width, canvas.height);
for(var i = 0; i < atlas.length; i++){
var path = atlas[i].path;
backgroundContext.beginPath();
if(path[0]){
backgroundContext.moveTo(path[0][0], path[0][1]);
}
for(var p = 1; p < path.length; p++){
backgroundContext.lineTo(path[p][0], path[p][1]);
}
backgroundContext.closePath();
backgroundContext.fill();
}
}
function render(path){
context.globalCompositeOperation = "source-over";
context.clearRect(0, 0, canvas.width, canvas.height);
if(highlightUncharted){
context.drawImage(backgroundCanvas, 0, 0);
context.fillStyle = "rgba(0, 0, 0, 0.4)";
} else {
context.fillStyle = "rgba(0, 0, 0, 0.6)";
}
context.fillRect(0, 0, canvas.width, canvas.height);
context.beginPath();
if(path[0]){
context.moveTo(path[0][0], path[0][1]);
}
for(var i = 1; i < path.length; i++){
context.lineTo(path[i][0], path[i][1]);
}
context.closePath();
context.strokeStyle = "rgba(255, 255, 255, 1)";
context.stroke();
context.globalCompositeOperation = "destination-out";
context.fillStyle = "rgba(0, 0, 0, 1)";
context.fill();
}
}