atlas/draw.js

291 lines
7.3 KiB
JavaScript

/*
========================================================================
The /r/place Atlas
An Atlas of Reddit's /r/place, with information to each
artwork of the canvas provided by the community.
Copyright (C) 2017 Roland Rytz <roland@draemm.li>
Licensed under the GNU Affero General Public License Version 3
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
========================================================================
*/
function initDraw(){
var finishButton = document.getElementById("finishButton");
var resetButton = document.getElementById("resetButton");
var undoButton = document.getElementById("undoButton");
var redoButton = document.getElementById("redoButton");
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");
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
];
});
container.addEventListener("mouseup", function(e){
if(Math.abs(lastPos[0] - e.clientX) + Math.abs(lastPos[1] - e.clientY) <= 4 && drawing){
path.push([
~~((e.clientX - (container.clientWidth/2 - innerContainer.clientWidth/2 + zoomOrigin[0]))/zoom)+0.5
,~~((e.clientY - (container.clientHeight/2 - innerContainer.clientHeight/2 + zoomOrigin[1]))/zoom)+0.5
]);
render(path);
undoHistory = [];
redoButton.disabled = true;
undoButton.disabled = false;
if(path.length >= 3){
finishButton.disabled = false;
}
}
});
window.addEventListener("mousemove", function(e){
if(!dragging && drawing){
var last = [
~~((e.clientX - (container.clientWidth/2 - innerContainer.clientWidth/2 + zoomOrigin[0]))/zoom)+0.5
,~~((e.clientY - (container.clientHeight/2 - innerContainer.clientHeight/2 + zoomOrigin[1]))/zoom)+0.5
];
render(path.concat([last]));
}
});
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";
}
});
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";
});
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;
exportOverlay.style.display = "block";
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";
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";
document.getElementById("nameField").value = "";
document.getElementById("descriptionField").value = "";
document.getElementById("websiteField").value = "";
document.getElementById("subredditField").value = "";
}
function render(path){
context.globalCompositeOperation = "source-over";
context.clearRect(0, 0, canvas.width, canvas.height);
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();
}
}