Last active
April 4, 2017 00:08
-
-
Save Grissess/0356ddc38790f216ae9c721697faa42c to your computer and use it in GitHub Desktop.
A possible Place-alike frontend
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>Place2 Mockup</title> | |
<meta charset="utf8"/> | |
<script type="text/javascript"> | |
/* Configuration section */ | |
var WIDTH = 500; | |
var HEIGHT = 500; | |
var PALETTE = [ | |
"#fff", | |
"#aaa", | |
"#555", | |
"#000", | |
"#f00", | |
"#f70", | |
"#ff0", | |
"#7f0", | |
"#0f0", | |
"#0f7", | |
"#0ff", | |
"#07f", | |
"#00f", | |
"#70f", | |
"#f0f", | |
"#f07", | |
]; | |
var INIT_SCALE = 16; // Pixels / texel at initial zoom | |
var ZOOM_SCALE = 64; // Pixels / texel when zoomed in | |
function sendColorUpdate(tx, ty, color_idx) { | |
// To be implemented | |
console.log(tx, ty, color_idx); | |
putColor(tx, ty, color_idx); // Force local update | |
} | |
// To be called whenever a pixel must be placed | |
function putColor(tx, ty, color_idx) { | |
ctx.fillStyle = PALETTE[color_idx]; | |
ctx.fillRect(tx, ty, 1, 1); | |
} | |
/* End configuration */ | |
var canvas, controls, ctx, palette_elems; | |
var zoomed = false, dragging = false, was_moved = false; | |
var cur_color = null; | |
var drag_elem = null; | |
var drag_rot = 0.0; | |
var canv_width = WIDTH, canv_height = HEIGHT; | |
var canv_top = 0, canv_left = 0; | |
var target_top = 0, target_left = 0; | |
var drag_top, drag_left; | |
function lerp(a, b, u) { | |
return (1 - u) * a + u * b; | |
} | |
function invertColor(hc) { | |
// FIXME: Only works for 3-component hex right now | |
if(hc.charAt(0) == '#') { | |
if(hc.length == 4) { | |
var cc = '#'; | |
for(var i = 1; i < 4; i++) { | |
cc += (15 - parseInt(hc.charAt(i), 16)).toString(16); | |
} | |
return cc; | |
} | |
} | |
} | |
function currentScale() { | |
return canvas.offsetWidth / canvas.width; | |
} | |
function desiredScale() { | |
return zoomed? ZOOM_SCALE : INIT_SCALE; | |
} | |
function animFrame() { | |
updateDragElem(); | |
updateCanvasProps(); | |
window.requestAnimationFrame(animFrame); | |
} | |
function updateDragElem() { | |
if(drag_elem != null) { | |
drag_elem.style.width = currentScale() + "px"; | |
drag_elem.style.height = currentScale() + "px"; | |
drag_rot = lerp(drag_rot, 0.0, 0.1); | |
drag_elem.style.transform = "rotate(" + drag_rot + "rad)"; | |
} | |
} | |
function updateCanvasProps() { | |
var target_width, target_height; | |
target_width = desiredScale() * WIDTH; | |
target_height = desiredScale() * HEIGHT; | |
if(Math.abs(canv_width - target_width) >= 1 || Math.abs(canv_height - target_height) >= 1) { | |
canv_width = lerp(canv_width, target_width, 0.5); | |
canv_height = lerp(canv_height, target_height, 0.5); | |
canvas.style.width = canv_width + "px"; | |
canvas.style.height = canv_height + "px"; | |
} | |
if(Math.abs(canv_left - target_left) >= 1 || Math.abs(canv_top - target_top) >= 1) { | |
canv_left = lerp(canv_left, target_left, 0.5); | |
canv_top = lerp(canv_top, target_top, 0.5); | |
canvas.style.left = -canv_left + "px"; | |
canvas.style.top = -canv_top + "px"; | |
} | |
} | |
function placeJump() { | |
canv_left = target_left; | |
canv_top = target_top; | |
canvas.style.left = -canv_left + "px"; | |
canvas.style.top = -canv_top + "px"; | |
} | |
function placeCornerTo(x, y) { | |
target_left = desiredScale() * x; | |
target_top = desiredScale() * y; | |
} | |
function placeCenterTo(x, y) { | |
var disp_width = window.innerWidth; | |
var disp_height = window.innerHeight; | |
target_left = desiredScale() * x - disp_width / 2; | |
target_top = desiredScale() *y - disp_height / 2; | |
} | |
function placeEnter(ev) { | |
if(cur_color != null && drag_elem == null) { | |
drag_elem = document.createElement("div"); | |
drag_elem.classList.add("drag"); | |
drag_elem.style.backgroundColor = PALETTE[cur_color]; | |
drag_elem.style.left = ev.pageX; | |
drag_elem.style.top = ev.pageY; | |
document.body.appendChild(drag_elem); | |
} | |
} | |
function placeLeave(ev) { | |
if(drag_elem != null) { | |
document.body.removeChild(drag_elem); | |
drag_elem = null; | |
} | |
} | |
function placeMove(ev) { | |
was_moved = true; | |
if(drag_elem != null) { | |
drag_elem.style.left = ev.pageX; | |
drag_elem.style.top = ev.pageY; | |
drag_rot = lerp(drag_rot, Math.atan(ev.movementX), 0.5); | |
} | |
if(dragging) { | |
target_left -= ev.movementX; | |
target_top -= ev.movementY; | |
placeJump(); | |
} | |
} | |
function placeClick(ev) { | |
if(was_moved) return; | |
if(cur_color != null && zoomed) { | |
sendColorUpdate( | |
Math.floor(ev.offsetX / currentScale()), | |
Math.floor(ev.offsetY / currentScale()), | |
cur_color | |
); | |
setCurrentColor(null); | |
} else { | |
zoomed = !zoomed; | |
placeCenterTo(ev.offsetX / currentScale(), ev.offsetY / currentScale()); | |
} | |
} | |
function placeMouseDown(ev) { | |
dragging = true; | |
was_moved = false; | |
placeJump(); | |
drag_top = target_top; | |
drag_left = target_left; | |
} | |
function placeMouseUp(ev) { | |
dragging = false; | |
} | |
function setCurrentColor(idx) { | |
if(cur_color != null) { | |
palette_elems[cur_color].style.border = ""; | |
} | |
if(idx == null) { | |
cur_color = null; | |
if(drag_elem != null) { | |
document.body.removeChild(drag_elem); | |
drag_elem = null; | |
} | |
return; | |
} | |
if(cur_color == idx) { | |
cur_color = null; | |
} else { | |
cur_color = idx; | |
if(drag_elem != null) { | |
drag_elem.style.backgroundColor = PALETTE[idx]; | |
} | |
palette_elems[idx].style.border = "2px solid " + invertColor(PALETTE[idx]); | |
} | |
} | |
function paletteClick(ev) { | |
var idx = parseInt(this.dataset.colorIdx); | |
setCurrentColor(idx); | |
} | |
function makeRandomNoise() { | |
for(var x = 0; x < WIDTH; x++) { | |
for(var y = 0; y < WIDTH; y++) { | |
putColor(x, y, Math.floor(Math.random() * PALETTE.length)); | |
} | |
} | |
} | |
function init() { | |
canvas = document.querySelector("#place"); | |
canvas.width = WIDTH; | |
canvas.height = HEIGHT; | |
canvas.addEventListener("mouseenter", placeEnter); | |
canvas.addEventListener("mouseleave", placeLeave); | |
canvas.addEventListener("mousemove", placeMove); | |
canvas.addEventListener("click", placeClick); | |
canvas.addEventListener("mousedown", placeMouseDown); | |
canvas.addEventListener("mouseup", placeMouseUp); | |
ctx = canvas.getContext("2d"); | |
controls = document.querySelector("#controls"); | |
palette_elems = new Array(PALETTE.length); | |
for(var i = 0; i < PALETTE.length; i++) { | |
var color = PALETTE[i]; | |
var elem = document.createElement("div"); | |
elem.addEventListener("click", paletteClick); | |
elem.dataset.colorIdx = i; | |
elem.style.backgroundColor = color; | |
controls.appendChild(elem); | |
palette_elems[i] = elem; | |
} | |
// Debugging | |
makeRandomNoise(); | |
animFrame(); | |
} | |
document.addEventListener("DOMContentLoaded", init); | |
</script> | |
<style type="text/css"> | |
#place { | |
position: fixed; | |
image-rendering: pixelated; | |
image-rendering: -moz-crisp-edges; | |
} | |
#controls { | |
position: fixed; | |
left: 0; | |
bottom: 0; | |
width: 100%; | |
display: flex; | |
justify-content: center; | |
background-color: #333; | |
} | |
#controls div { | |
margin: 10px; | |
width: 25px; | |
height: 25px; | |
border: 2px solid rgba(0, 0, 0, 0); | |
} | |
.drag { | |
position: fixed; | |
} | |
</style> | |
</head> | |
<body> | |
<canvas id="place"></canvas> | |
<div id="controls"> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment