説明なし

index.html 7.9KB

    <!doctype html> <html> <head> <title>.pixl</title> <meta charset="utf-8" /> <style type="text/css"> body { overflow: hidden; } canvas { position: absolute; top: 0; left: 0; } #status { position: absolute; bottom: 0; right: 0; } #pos, #online { display: inline-block; vertical-align: bottom; } #online { width: 20px; height: 20px; background-color: green; } </style> </head> <body> <canvas id="stage"></canvas> <span id="status"> <span id="pos"></span> <span id="online"></span> </span> <script> window.polyfill = {}; polyfill.movement = function(ev) { ev.movementX = ev.movementX || ev.mozMovementX || ev.webkitMovementX; ev.movementY = ev.movementY || ev.mozMovementY || ev.webkitMovementY; return ev; }; Math.sign = Math.sign || function(n) { if (n < 0) { return -1; } else if (n > 0) { return 1; } else { return 0; } }; </script> <script> window.pixl = {}; pixl.stage = document.querySelector("#stage"); pixl.ctx = stage.getContext("2d"); pixl.status = { pos: document.querySelector("#pos"), online: document.querySelector("#online") }; pixl.window = {w: window.innerWidth, h: window.innerHeight}; pixl.world = {}; pixl.pos = {x: 0, y: 0}; pixl.color = "black"; pixl.size = 20; pixl.stage.width = pixl.window.w; pixl.stage.height = pixl.window.h; pixl.to_world = function(screen_pos) { return {x: Math.floor((screen_pos.x - pixl.window.w / 2 + pixl.pos.x * pixl.size) / pixl.size), y: Math.floor((screen_pos.y - pixl.window.h / 2 + pixl.pos.y * pixl.size) / pixl.size)}; } pixl.to_screen = function(world_pos) { return {x: pixl.window.w / 2 + (world_pos.x - pixl.pos.x) * pixl.size, y: pixl.window.h / 2 + (world_pos.y - pixl.pos.y) * pixl.size}; } pixl.area = {}; pixl.area.w2 = function() { return Math.round(pixl.window.w / pixl.size / 2); }; pixl.area.h2 = function() { return Math.round(pixl.window.h / pixl.size / 2); }; pixl.at = function(pos) { var p = pixl.world[pos.x + "," + pos.y]; return p !== undefined && p.color !== "white"; } pixl.draw_pixl = function(pos, color, options) { var color = color || pixl.color; pixl.ctx.fillStyle = color; var options = options || {}; var pos = options.rawValue ? pos : {x: Math.round(pos.x), y: Math.round(pos.y)}; var screen_pos = pixl.to_screen(pos); pixl.ctx.fillRect(screen_pos.x, screen_pos.y, pixl.size, pixl.size); pixl.world[pos.x + "," + pos.y] = {color: color}; var send = options.hasOwnProperty('send') ? options.send : true; if (pixl.online && send) { pixl.ws.send(JSON.stringify([{x: pos.x, y: pos.y, color: color}])); } } pixl.redraw = function() { pixl.ctx.clearRect(0, 0, pixl.window.w, pixl.window.h); var w2 = Math.round(pixl.window.w / pixl.size / 2); var h2 = Math.round(pixl.window.h / pixl.size / 2); for (var x = pixl.pos.x - w2; x < pixl.pos.x + w2; x++) { for (var y = pixl.pos.y - h2; y < pixl.pos.y + h2; y++) { var pt = pixl.world[[x, y]]; if (pt !== undefined) { pixl.draw_pixl({x: x, y: y}, pt.color, {send: false}); } } } } pixl.redraw(); pixl.stage.addEventListener("wheel", function(ev) { ev.preventDefault(); pixl.size += (pixl.size / 10) * Math.sign(ev.deltaY); if (pixl.size < 5) { pixl.size = 5; } else if (pixl.size > pixl.window.w / 2) { pixl.size = Math.round(pixl.window.w / 2); } requestAnimationFrame(pixl.redraw); }); window.addEventListener("resize", function(ev) { pixl.window.w = window.innerWidth; pixl.window.h = window.innerHeight; pixl.stage.width = pixl.window.w; pixl.stage.height = pixl.window.h; pixl.redraw(); }); pixl.status.online.addEventListener("click", function(ev) { if (pixl.online) { pixl.disconnect(); } else { pixl.connect(); } }); pixl.drag = {start: undefined, current: undefined}; pixl.stage.addEventListener("mousedown", function(ev) { /*if (document.mozPointerLockElement === null) { document.addEventListener("mozpointerlockerror", console.log.bind(console)); pixl.stage.mozRequestPointerLock(); }*/ pixl.drag.start = {x: ev.clientX, y: ev.clientY}; pixl.drag.pos = pixl.pos; }); pixl.stage.addEventListener("mousemove", function(ev) { if (pixl.drag.start !== undefined) { pixl.drag.current = {x: ev.clientX, y: ev.clientY}; } var hovered = pixl.to_world({x: ev.clientX, y: ev.clientY}); pixl.status.pos.textContent = hovered.x + "," + hovered.y; }); pixl.stage.addEventListener("mouseup", function(ev) { if (pixl.drag.current === undefined) { var ev = polyfill.movement(ev); var world_pos = pixl.to_world({x: ev.clientX, y: ev.clientY}); pixl.draw_pixl(world_pos, pixl.at(world_pos) ? "white" : pixl.color); } else { console.error("drag not implemented"); } pixl.drag = {}; }); document.addEventListener("keydown", function(ev) { if (ev.keyCode >= 37 && ev.keyCode <= 40) { switch (ev.keyCode) { case 37: // left pixl.pos.x -= 1; break; case 38: // up pixl.pos.y -= 1; break; case 39: // right pixl.pos.x += 1; break; case 40: // down pixl.pos.y += 1; break; } pixl.redraw(); } }); pixl.online = false; pixl.connect = function() { var protocol = location.protocol == 'https:' ? 'wss://' : 'ws://'; pixl.ws = new WebSocket(protocol + (location.host || 'localhost:8001') + '/ws'); pixl.ws.onopen = function() { pixl.online = true; pixl.status.online.style.backgroundColor = "green"; }; pixl.ws.onclose = function() { pixl.online = false; pixl.status.online.style.backgroundColor = "red"; }; pixl.ws.onmessage = function(msg) { var obj = JSON.parse(msg.data); if (obj.length !== undefined) { obj.forEach(function(p) { pixl.draw_pixl(p, p.color, {send: false}); }); } else { pixl.world = obj; pixl.redraw(); } }; }; pixl.disconnect = function () { pixl.ws.close(); }; pixl.connect(); pixl.disconnectAndClear = function() { pixl.disconnect(); pixl.world = {}; pixl.redraw(); } </script> <script> pixl.scripts = {}; pixl.scripts.stringify = function(name, scriptObj) { var script = "window." + name + " = " + "{};\n"; for (var fnName in scriptObj) { var fn = scriptObj[fnName]; script += name + "." + fnName + " = " + fn.toString() + ";\n"; if (fn.doc) { script += name + "." + fnName + ".doc = " + JSON.stringify(fn.doc) + ";\n"; } } return script; }; pixl.scripts.save = function(name, scriptObj) { var xhr = new XMLHttpRequest(); xhr.open('POST', '/scripts/' + name); xhr.send(pixl.scripts.stringify(name, scriptObj)); }; pixl.scripts.load = function(name) { var xhr = new XMLHttpRequest(); xhr.open('GET', '/scripts/' + name); xhr.onreadystatechange = function(ev) { if (xhr.readyState == 4) { var code = xhr.responseText; eval(code); } } xhr.send(); }; pixl.scripts.list = function() { var xhr = new XMLHttpRequest(); xhr.open('GET', '/scripts'); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { var scripts = xhr.responseText.split("\n"); for (var i = 0; i < scripts.length; i++) { console.log(scripts[i]); } } }; xhr.send(); } </script> </body> </html>