var contentType = 'text/plain;charset=utf-8' var cols = 80 var rows = 24 var dragging = false var drawing = true var erasing = false var focused var canvas, tools, palette, brush, mode, current_tool var color_names = ("white black dark-blue green red dark-red purple orange " + "yellow lime dark-cyan cyan blue magenta dark-gray light-gray").split(" "); var color_hue_order = ("black dark-blue purple dark-red red orange " + "yellow lime green dark-cyan cyan blue magenta dark-gray light-gray white").split(" "); var letters = "abcdefghijklmnop"; var colors = {}, controls = {} color_names.forEach(function(name, i){ colors[name] = i }) function init () { build() bind() } function build () { canvas = new Matrix (cols, rows, function(x,y){ var lex = new Lex (x,y) // lex.build() return lex }) shader.init() shader.run(canvas) brush = new Matrix (5, 5, function(x,y){ var lex = new Lex (x,y) lex.build() return lex }) palette = new Matrix (32, 2, function(x,y){ var lex = new Lex (x,y) lex.bg = colors[color_hue_order[y>>1]] lex.build() return lex }) canvas.append(canvas_rapper) brush.append(brush_rapper) palette.append(palette_rapper) controls.circle = new Tool (circle_el) controls.circle.use = function(){ brush.generate = controls.circle.generate brush.generate() drawing = true } controls.circle.generate = function(){ var fg = brush.fg, bg = brush.bg var hw = brush.w/2|0, hh = brush.h/2|0 brush.forEach(function(lex,x,y) { var len = Math.sqrt(Math.pow(x-hw,2)+Math.pow(y-hh,2)) if (len > Math.abs(hw)) { lex.clear() } else { lex.fill(fg,bg) } }) } controls.square = new Tool (square_el) controls.square.use = function(){ brush.generate = controls.square.generate brush.generate() drawing = true } controls.square.generate = function(){ var fg = brush.fg, bg = brush.bg brush.fill(fg,bg) } controls.text = new Tool (text_el) controls.text.use = function(){ brush.generate = controls.text.generate brush.generate() drawing = false } controls.text.generate = function(){ } controls.clear = new Tool (clear_el) controls.clear.use = function(){ canvas.clear() } controls.grid = new Tool (grid_el) controls.grid.use = function(){ document.body.classList.toggle('grid') } controls.shader = new Tool (shader_el) controls.shader.use = function(){ shader_textarea.style.display = "block" setTimeout(function(){ shader_textarea.focus() }) } controls.shader.blur = function(){ Tool.prototype.blur.call(this) shader_textarea.style.display = "none" } shader_textarea.value = demo_shader.innerHTML shader_textarea.addEventListener("input", function(){ var fn = shader.build(shader_textarea.value) fn && shader.run(canvas) }) controls.width = new Lex (width_el) controls.height = new Lex (height_el) controls.canvas_width = new Lex (canvas_width_el) controls.canvas_height = new Lex (canvas_height_el) controls.circle.focus() brush.bg = colors.red brush.generate() brush.build() } function bind () { canvas.forEach(function(lex, x, y){ lex.span.addEventListener('contextmenu', function(e){ e.preventDefault() }) lex.span.addEventListener('mousedown', function(e){ e.preventDefault() dragging = true if (drawing) { erasing = (e.which == "3" || e.ctrlKey) draw(lex, x, y, erasing) } lex.focus() }) lex.span.addEventListener("mousemove", function(){ if (! dragging) return if (drawing) { draw(lex, x, y, erasing) } lex.focus() }) }) palette.forEach(function(lex, x, y){ lex.span.addEventListener('mousedown', function(e){ e.preventDefault() dragging = true erasing = e.which == "3" brush.fg = lex.fg brush.bg = lex.bg brush.generate() }) }) brush.forEach(function(lex, x, y){ lex.span.addEventListener('mousedown', function(e){ e.preventDefault() dragging = true // lex.fill(lex.fg, lex.bg) }) }) window.addEventListener('mouseup', function(){ dragging = erasing = false }); [controls.width, controls.height, controls.canvas_width, controls.canvas_height].forEach(function(lex){ lex.span.addEventListener('mousedown', function(e){ lex.focus() }) }); [controls.square, controls.circle, controls.text, controls.clear, controls.grid, controls.shader].forEach(function(tool){ tool.span.addEventListener('mousedown', function(e){ tool.focus() }) }) controls.width.key = int_key(function(n, keyCode){ controls.width.blur() controls.width.char = ""+n controls.width.build() brush.w = n brush.rebuild() }) controls.height.key = int_key(function(n, keyCode){ controls.height.blur() controls.height.char = ""+n controls.height.build() brush.h = n brush.rebuild() }) controls.canvas_width.key = int_key(function(n, keyCode){ controls.canvas_width.read() if (controls.canvas_width.char.length == 1) { n = parseInt(controls.canvas_width.char) * 10 + n } controls.canvas_width.char = ""+n controls.canvas_width.build() canvas.w = n canvas.rebuild() canvas.build() }) controls.canvas_height.key = int_key(function(n, keyCode){ controls.canvas_height.read() if (controls.canvas_height.char.length == 1) { n = parseInt(controls.canvas_height.char) * 10 + n } controls.canvas_height.char = ""+n controls.canvas_height.build() canvas.h = n canvas.rebuild() canvas.build() }) window.addEventListener('keydown', function(e){ if (current_tool.name == "shader") { return } if (! e.metaKey && ! e.ctrlKey && ! e.altKey) { e.preventDefault() } // console.log(e.keyCode) switch (e.keyCode) { case 27: // esc if (focused) focused.blur() break case 219: // [ if (! focused && current_tool.name != "text") { brush.contract(1) break } case 221: // ] if (! focused && current_tool.name != "text") { brush.expand(1) break } default: if (focused) focused.key(String.fromCharCode(e.keyCode), e.keyCode) break } }) document.addEventListener('DOMContentLoaded', function(){ document.body.classList.remove('loading') }) } function int_key (f) { return function (key, keyCode) { var n = parseInt(key) ! isNaN(n) && f(n) } } function clamp (n,a,b){ return n < a ? a : n < b ? n : b } function mod (i,n) { return i - n * Math.floor(i / n) } document.body.addEventListener('copy', function (e) { if (e.clipboardData) { e.preventDefault(); e.clipboardData.setData(contentType, canvas.ascii()); } if (window.clipboardData) { e.returnValue = false; window.clipboardData.setData(contentType, canvas.ascii()); } }, false); init()