var mouseDown = 0; document.body.onmousedown = function() { mouseDown=1; } document.body.onmouseup = function() { mouseDown=0; } function get_back_pos(ele){//fuck IE here! var bp = $(ele).css('background-position'); if (typeof(bp)=="undefined") return $(ele).css("background-position-x")+" "+$(ele).css("background-position-y"); return bp; } function set_backpos_x(ele, val){//fuck firefox here! var posY = get_back_pos(ele).split(' ')[1]; $(ele).css('background-position', val+"px "+posY); } function set_backpos_y(ele, val){ var posX = get_back_pos(ele).split(' ')[0]; $(ele).css('background-position', posX+" "+val+"px"); } //---------draw_xxx objects----------- var g_draw = null; var g_history = [];//each element is a {num1:[bk_old1,bk_new1],...} map(to save dup dots) var g_history_pos = -1; var g_rightbutton = null; function push_history(dots){ g_history = g_history.slice(0, g_history_pos+1); g_history.push(dots); g_history_pos = g_history.length-1; set_xxdo_status(); window.onbeforeunload=function(){return "Your new drawings not saved yet!";}; } function is_right_mouse(e){ if (!e) e = window.event; return e.button & 2;//left:1, right:2, middle:3 } function set_mouse(e){ g_rightbutton = is_right_mouse(e); } function get_bk(num){ var jqobj = $("#pbd" + num); if (jqobj.hasClass("trans")) return null; return jqobj.css("background-color"); } function draw_pixel(bk, num){ if (!bk) bk=""; $("#pbd" + num).css("background-color", bk); $("#pbd" + num).toggleClass("trans", !bk); $("#p64" + num).css("background-color", bk); $("#p32" + num).css("background-color", bk); $("#p16" + num).css("background-color", bk); } function redraw_dots(dots){for(num in dots){var bk=dots[num][1];draw_pixel(bk,num);}} function reverse_dots(dots){for(num in dots){var bk=dots[num][0];draw_pixel(bk,num);}} function draw_dot(){ this.dots = {}; this.obks = {}; this.make_dot = function(bk, num){ var obk=get_bk(num); draw_pixel(bk,num); this.dots[num]=[this.obks[parseInt(num, 10)],bk]; }; this.on_down = function(bk, num){ for (var x=0;x<16;x++) for (var y=0;y<16;y++) this.obks[y*16+x]=get_bk(y*16+x); this.make_dot(bk,num); }; this.on_move = function(bk, num){this.make_dot(bk,num);}; this.on_up = function(bk, num){push_history(this.dots);this.dots={};this.obks={};}; } function draw_block(){ this.dots = {}; this.obks = {}; this.make_block = function(bk, num){ var num = parseInt(num, 10); var nums = [num]; if (num%16 < 15) nums.push(num+1); if (num/16 < 15) nums.push(num+16); if (nums.length == 3) nums.push(num+16+1); for(var i=0;i0?1:-1); var y = sy + d; var x = sx + (dy?Math.floor(d*dx/dy+0.5):d); nums.push(y*16+x); } }else{ for (i=0;i<=dxa;i++){ var d = i*(dx>0?1:-1); var x = sx + d; var y = sy + (dx?Math.floor(d*dy/dx+0.5):d); nums.push(y*16+x); } } return nums; } function draw_line(){ this.start = null;//line start this.dots = {}; this.make_line = function(bk, num){ //rubber band reverse_dots(this.dots); this.dots={}; var nums = calc_line_nums(this.start, num); for (var i=0;i0?1:-1); nums.push(sy*16+d+sx); nums.push(ey*16+d+sx); } for(i=0; i<=dya; i++){ d = i*(dy>0?1:-1); nums.push((sy+d)*16+sx); nums.push((sy+d)*16+ex); } return nums; } function draw_rect(){ this.start = null;//line start this.dots = {}; this.make_rect = function(bk, num){ //rubber band reverse_dots(this.dots); this.dots={}; var nums = calc_rect_nums(this.start, num); for (var i=0;i0) try_add(x-1, y); if (x<15)try_add(x+1, y); if (y>0) try_add(x, y-1); if (y<15)try_add(x, y+1); pos++; } return nums; } function draw_fill(){ this.on_down = function(bk, num){ var dots={}; var nums = calc_fill_nums(num); for (var i=0;i= 0 && x+dx < 16 && y+dy >=0 && y+dy < 16){ return this.bks[(y+dy)*16+x+dx]; } return null; } this.move_to = function(num){ var dxy = this.calc_dxy(num); var dx = dxy[0]; var dy = dxy[1]; for (var y=0;y<16;y++) for (var x=0;x<16;x++) draw_pixel(this.bk_dxy(x,y,dx,dy), y*16+x); } this.on_down = function(bk, num){this.from=num;if(!this.bks)this.init();} this.on_move = function(bk, num){this.move_to(num);} this.on_up = function(bk, num){ var odx = this.dxy[0]; //old dx var ody = this.dxy[1]; //old dy this.dxy = this.calc_dxy(num); var dx = this.dxy[0]; var dy = this.dxy[1]; for (var y=0;y<16;y++){ for (var x=0;x<16;x++){ var bk = this.bk_dxy(x,y,dx,dy); var obk = this.bk_dxy(x,y,odx,ody); if (bk!=obk) this.dots[y*16+x]=[obk,bk]; } } push_history(this.dots); this.dots={}; this.from=null; } } //---------operations----------------- function set_xxdo_status(){ set_backpos_x($("#_undo")[0], g_history_pos>=0?-324:-360); set_backpos_x($("#_redo")[0], g_history_pos= g_history.length-1) return; g_history_pos++; var dots = g_history[g_history_pos]; redraw_dots(dots); set_xxdo_status(); } function _clean(){ var dots={}; for (var x=0;x<16;x++) for (var y=0;y<16;y++) dots[y*16+x] = [get_bk(y*16+x),null]; redraw_dots(dots); push_history(dots); } function _save(){ window.onbeforeunload=function(){return;}; var colors = []; for (var i=0;i<16*16;i++) { var bk = get_bk(i); if (!bk) { colors = colors.concat([0, 0, 0, 1]); continue; } var rgb = (bk.charAt(0)=="#") ? hex2rgb(bk) : color2rgb(bk); colors = colors.concat([rgb.r, rgb.g, rgb.b, 0]); } $("#colors").val(colors.join(",")); $("#downicon").submit(); } function add_to_mru(bk){ if (bk) {//add to mru var found=false; $("#mrucolors div").each(function(){ if ($(this).css("background-color")==bk) { $("#mrucolors").append($(this)); found = true; } }); if (!found){ if ($("#mrucolors div").length >= 5) $("#mrucolors div").eq(0).remove(); $("#mrucolors div:last").clone().appendTo($("#mrucolors")).css("background-color", bk); } } } var g_last_state = null; function color_it(e, action){//action could be "down"/"move"/"up" var obj = e.target; if (obj.id.substring(0,3) != "pbd") return; var num = obj.id.substring(3); if (mouseDown <= 0) return; var colo = g_rightbutton ? $("#currback") : $("#currfront"); var flag = colo.hasClass("trans"); var bk = flag ? null : colo.css("background-color"); //avoid duplicate calculations for subtle mousemove if (action == "move") { if (g_last_state == num+bk) return; g_last_state = num+bk; } else g_last_state = null; add_to_mru(bk); //invoke handler if (action == "down") g_draw.on_down(bk, num); else if (action == "move") g_draw.on_move(bk, num); else g_draw.on_up(bk, num); } function XOR(a,b){return (a||b)&&!(a&&b);} function hexify(number){ number = Math.floor(number); var digits = '0123456789abcdef'; var lsd = number % 16; var msd = Math.floor((number - lsd) / 16); var hexified = digits.charAt(msd) + digits.charAt(lsd); return hexified; } function decimalize(hexNumber){ var digits = '0123456789abcdef'; return ((digits.indexOf(hexNumber.charAt(0).toLowerCase()) * 16) + digits.indexOf(hexNumber.charAt(1).toLowerCase())); } function hex2rgb(colorString){ var rgb = Object(); rgb.r = decimalize(colorString.substring(1,3)); rgb.g = decimalize(colorString.substring(3,5)); rgb.b = decimalize(colorString.substring(5,7)); return rgb; } function rgb2hex(rgb){return "#"+hexify(rgb.r)+hexify(rgb.g)+hexify(rgb.b);} function rgb2hsv(rgb){ var hsv = Object(); r = rgb.r / 255; g = rgb.g / 255; b = rgb.b / 255; // Scale to unity. var minVal = Math.min(r, g, b); var maxVal = Math.max(r, g, b); var delta = maxVal - minVal; hsv.v = maxVal; if (delta == 0) { hsv.h = 0; hsv.s = 0; } else { hsv.s = delta / maxVal; var del_r = (((maxVal - r) / 6) + (delta / 2)) / delta; var del_g = (((maxVal - g) / 6) + (delta / 2)) / delta; var del_b = (((maxVal - b) / 6) + (delta / 2)) / delta; if (r == maxVal) {hsv.h = del_b - del_g;} else if (g == maxVal) {hsv.h = (1 / 3) + del_r - del_b;} else if (b == maxVal) {hsv.h = (2 / 3) + del_g - del_r;} if (hsv.h < 0) {hsv.h += 1;} if (hsv.h > 1) {hsv.h -= 1;} } hsv.h = Math.floor(hsv.h*360); hsv.s = Math.floor(hsv.s*100); hsv.v = Math.floor(hsv.v*100); return hsv; } //http://en.wikipedia.org/wiki/HSL_and_HSV function hsv2rgb(hsv){ var rgb = Object(); var h = hsv.h / 360; var s = hsv.s / 100; var v = hsv.v / 100; if (hsv.s == 0) { rgb.r = v * 255; rgb.g = v * 255; rgb.b = v * 255; } else { h = h * 6; var hi = Math.floor(h); var f = h - hi; var p = v * (1 - s); var q = v * (1 - s * (h - hi)); var t = v * (1 - s * (1 - (h - hi))); var rgba = [[v,t,p], [q,v,p], [p,v,t],[p,q,v],[t,p,v],[v,p,q]]; var rgbai = rgba[hi]; rgb.r = Math.floor(rgbai[0]* 255); rgb.g = Math.floor(rgbai[1]* 255); rgb.b = Math.floor(rgbai[2]* 255); } return rgb; } function _O(a){$("#statusbar").text(a.join(","));} function move_wheel(hsv){ //var hsv = {"h":angle, "s":r, "v":100}; var angle = hsv.h; if (angle>180) angle = Math.floor((180+angle)*2/3); else angle = Math.floor(angle*3/2); var r = Math.floor(hsv.s*80/100); var x = r*Math.cos(angle*Math.PI/180); var y = -r*Math.sin(angle*Math.PI/180); var R = 78; $("#cross").css({"left":(R+x)+"px", "top":(R+y)+"px"}); } function move_slider(val){ var left = Math.floor((100 - val) * 165 / 100); left = (left>=165)?164:left; left -= 11; $("#slider").css("left", left + "px"); } function wheel(e,obj) { if (mouseDown < 1) return; var jqobj = $("#colorwheel"); var x = e.pageX - jqobj.offset().left - 2; //2 is the wheel border var y = e.pageY - jqobj.offset().top - 2; var R = 80; var dx = x - R; var dy = R - y; var r = Math.ceil(Math.sqrt(dx*dx + dy*dy) * 100 / 80); if (r>105) return; //5 pixels sensitive border if (r>100) r = 100; var angle = null; angle = Math.floor(Math.atan2(dy, dx)*180/Math.PI+360)%360; if (angle >= 240) angle = Math.floor(angle * 3 / 2 - 180); else angle = Math.floor(angle*2/3); //calc hsv var hsv = {"h":angle, "s":r, "v":100}; $("#slidebar").data("hsv", hsv);//save to bar var rgb = rgb2hex(hsv2rgb(hsv)); var colo = $("#currfront"); if (g_rightbutton) colo = $("#currback") colo.css("background-color", rgb); //move slider $("#slidebar").css("background-color", rgb); move_slider(100); $("#cross").css({"left":x-6+"px", "top":y-4+"px"}); set_color_info(hsv2rgb(hsv)); } function slider(e,obj){ if (mouseDown < 1) return; var jqobj = obj?$(obj):$(this); var x = e.pageX - jqobj.offset().left; x = (x>165)?165:((x<0)?0:x); var hsv = jqobj.data("hsv"); hsv.v = Math.floor((165-x) * 100 / 165); move_slider(hsv.v); var rgb = rgb2hex(hsv2rgb(hsv)); var colo = $("#currfront"); if (g_rightbutton) colo = $("#currback") colo.css("background-color", rgb); set_color_info(hsv2rgb(hsv)); } function color2rgb(color){ var parts = color.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); return {"r":parts[1], "g":parts[2], "b":parts[3]}; } function set_color_info(rgb){ $("#rgbhex").val(rgb2hex(rgb).substring(1)); $("#rgbR").val(rgb.r); $("#rgbG").val(rgb.g); $("#rgbB").val(rgb.b); var hsv = rgb2hsv(rgb); $("#hsvH").val(hsv.h); $("#hsvS").val(hsv.s); $("#hsvV").val(hsv.v); } function sync_colorpick(color){ var rgb = (color.charAt(0)=="#") ? hex2rgb(color) : color2rgb(color); var hsv = rgb2hsv(rgb); var fullcolor = rgb2hex(hsv2rgb({"h":hsv.h, "s":hsv.s, "v":100})); $("#slidebar").css("background-color", fullcolor); move_slider(hsv.v); $("#slidebar").data("hsv", hsv); move_wheel(hsv); set_color_info(rgb); } function color_info_updated(obj){ var rgbhex = null; if (obj.id == "rgbhex"){ rgbhex = "#"+$(obj).val(); }else if(obj.id.substring(0,3)=="rgb"){ var r = parseInt($("#rgbR").val(), 10); var g = parseInt($("#rgbG").val(), 10); var b = parseInt($("#rgbB").val(), 10); rgbhex = "#"+hexify(r)+hexify(g)+hexify(b); }else{ var h = parseInt($("#hsvH").val(), 10); var s = parseInt($("#hsvS").val(), 10); var v = parseInt($("#hsvV").val(), 10); rgbhex = rgb2hex(hsv2rgb({"h":h, "s":s, "v":v})); } var colo = $("#currfront"); colo.removeClass("trans"); colo.css("background-color", rgbhex); sync_colorpick(rgbhex); } function select_tool(obj){ g_draw = eval("new " + obj.id + "()"); $("#toolbar div").each(function(){set_backpos_y(this,0);}); set_backpos_y(obj, -70); g_last_selected = g_selected; g_selected = obj; var action = obj.id.substring(5); var cursor = "url(/static/images/tool/"+action+".cur),pointer"; var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;//@@Hack!!!shit chrome if (is_chrome){ if (action == "move") cursor = "move"; else if (action == "line") cursor = "text"; else if (action == "rect") cursor = "crosshair"; } $("#board").css("cursor", cursor); } //init $(function(){ var cibds = []; var ci64s = []; var ci32s = []; var ci16s = []; var i=0; var j=0; for (i=0; i<16; i++) { for (var j=0; j<16; j++) { var ij = i*16+j; cibds.push('
'); ci64s.push('
'); ci32s.push('
'); ci16s.push('
'); } } $("#board").html(cibds.join("")); $("#ci64").html(ci64s.join("")); $("#ci32").html(ci32s.join("")); $("#ci16").html(ci16s.join("")); $("#board").mousedown(function(e){mouseDown=1;set_mouse(e);color_it(e, "down");mouseDown=0;}); $("#board").mousemove(function(e){color_it(e, "move");}); $("#board").mouseup(function(e){color_it(e, "up");}); //disable_right_menu $("#iconpanel")[0].oncontextmenu = function() {return false;}; $("#iconpanel")[0].onselectstart = function() {return false;}; //swap front/back $("#currswap").click(function(e){ var bktemp = $("#currfront").css("background-color"); $("#currfront").css("background-color", $("#currback").css("background-color")); $("#currback").css("background-color", bktemp); var flag = XOR($("#currfront").hasClass("trans"), $("#currback").hasClass("trans")); if (flag) { $("#currfront").toggleClass("trans"); $("#currback").toggleClass("trans"); } }); //transparent front/back $("#transcolor").mousedown(function(e){ var colo = $("#currfront"); if (is_right_mouse(e)) colo = $("#currback") colo.addClass("trans"); }); //preset colors var pres = "000000 800000 008000 000080 008080 800080 808000 996600 c0c0c0 808080 ff0000 00ff00 0000ff 00ffff ff00ff ffff00 cc9900 ffffff ffcc00 ffff99 d93600 ff794b ff9933 ffdb9d 6666cc 9999ff ccccff ffccff 0066cc 0099ff 99ccff d2eeff 009900 66cc33 99ff66 ccffcc"; pres = pres.split(" "); var cs=""; var U=27; var B=2; for(i=0;i'; } cs += '
'; $("#precolors").html(cs); var last_pre = null; $("#precolors div").mousedown(function(e){ var colo = $("#currfront"); if (is_right_mouse(e)) colo = $("#currback") colo.removeClass("trans"); var bk = $(this).css("background-color"); colo.css("background-color", bk); sync_colorpick(bk); }).hover(function(){ if (last_pre == this || !$(this).hasClass("precolor")) return; last_pre = this; $("#prewrap").show(); var bk = $(this).css("background-color"); var x = parseInt($(this).css("left"), 10) - 5; var y = parseInt($(this).css("top"), 10) - 5; $("#prewrap").css({"left": x, "top": y, "background-color":bk}); }); $("#prewrap").hover(null, function(){$(this).hide();}); $("#colorwheel").mousedown(function(e){mouseDown=1;set_mouse(e);wheel(e);mouseDown=0;}); $("#colorwheel").mousemove(wheel); $("#slidebar").mousedown(function(e){mouseDown=1;set_mouse(e);slider(e,this);mouseDown=0;}); $("#slidebar").mousemove(slider); sync_colorpick("#000000"); //sync color info $("#colorinfo input").change(function(){color_info_updated(this);}); $("#colorinfo input").keydown(function(eve){if(eve.keyCode==13)color_info_updated(this);}); //recent colors $("#mrucolors").html('
'); $("#mrucolors div").live("mousedown", function(e){ var colo = $("#currfront"); if (is_right_mouse(e)) colo = $("#currback") colo.removeClass("trans"); var bk = $(this).css("background-color"); colo.css("background-color", bk); sync_colorpick(bk); }); //create toolbar icons var icons = [ ["dot", 0, -70, 1, "space"], ["block", -36, 0, 1, "d"], ["line", -72, 0, 1, "e"], ["rect", -108, 0, 1, "r"], ["fill", -144, 0, 1, "f"], ["magic", -180, 0, 1, "g"], ["move", -288, 0, 1, "m"], ["pick", -216, 0, 1, "a"], ["clean", -252, 0, 0, "x"], ["undo", -324, 0, 0, "z"], ["redo", -396, 0, 0, "y"], ["save", -468, 0, 0, "s"]]; var html = ""; for(i=0;i'; } $("#toolbar").html(html); $("#toolbar div").hover(function(){ set_backpos_y(this, -35); },function(){ set_backpos_y(this, this==g_selected?-70:0); }); $("#toolbar div").click(function(){ if ($(this).hasClass("draw")) select_tool(this); else eval(this.id + "()"); }); $("#toolbar div").each(function(){ var hotkey = $(this).attr("title"); var jqobj = $(this); $(document).bind('keydown', hotkey, function(eve){jqobj.click();}); }); g_draw = new draw_dot(); g_selected = $("#toolbar div").eq(0)[0]; set_xxdo_status(); //hotkeys $(document).bind('keyup', 'Ctrl+z', _undo); $(document).bind('keyup', 'Ctrl+y', _redo); $(document).bind('keyup', 'Ctrl+x', _clean); $(document).bind('keyup', 'Ctrl+c', _save); });