Home » Demos » Pixelbox

Pixelbox

Greatest draws



About this demo


Pixelbox is a collaborative drawing tool, simple but fast. Have fun with friends! :) Don't forget to save your piece of pixel art!

Keyboard shortcuts:

Eye dropper Ctrl or Alt + Click

Draw a line: Click then Shift + Click

Switch colors: X

Which features this demo is using?

  • nickname.js
  • Sessions
  • Http.js
  • ServerSide JavaScript



A simple chat demo, multi-user and private messages.

APE real time chat

A simple chat demo, multi-user and private messages.

Demo of multi-user moving and chating in real time.

Move demo

Demo of multi-user moving and chating in real time.

Live tweets from Twitter trends, in real time!

Live tweets

Live tweets from Twitter trends, in real time!


Gateway to IRC using the TCPSocket feature. Come chat with us ;)

TCPSocket Demo (IRC)

Gateway to IRC using the TCPSocket feature. Come chat with us ;)

A demo of a small massive multiplayer role playing game!

MMORPG

A demo of a small massive multiplayer role playing game!

Draw with everyone in real time!

Pixelbox

Draw with everyone in real time!


Homepage demo

Homepage demo

This is the demo from the home page of APE, but you've probably already seen it ;-)


Study the source code


Check out the Client JavaScript, HTML and ServerSide JavaScript source code of this demo by reading the following :


  1. <!--[if IE]>
  2. <div class="note">This demo might be laggy on Internet Explorer, because canvas are emulated.</div>
  3. <![endif]-->
  4. <link rel="stylesheet" type="text/css" href="http://static.weelya.com/weelya_ape/demos/pixelbox/pixelbox.css" />
  5. <link rel="stylesheet" type="text/css" href="http://static.weelya.com/weelya_ape/demos/pixelbox/moorainbow.css" />
  6. <link rel="stylesheet" type="text/css" href="http://static.weelya.com/weelya_ape/demos/pixelbox/ReMooz/ReMooz.css" />
  7. <!--[if IE]><script type="text/javascript" src="/demos/mmo/excanvas.js"></script><![endif]-->
  8. <script type="text/javaScript" src="http://static.weelya.com/weelya_ape/demos/pixelbox/mootools.drag.color.js"></script>
  9. <script type="text/javaScript" src="http://static.weelya.com/weelya_ape/demos/pixelbox/moorainbow.modified.js"></script>
  10. <script type="text/javaScript" src="http://static.weelya.com/weelya_ape/demos/pixelbox/ReMooz/ReMooz.js"></script>
  11. <script type="text/javaScript" src="http://static.weelya.com/weelya_ape/demos/pixelbox/pixelbox.js"></script>
  12. <script type="text/javascript">
  13. //<!--
  14.         var list = ["Image 1.png",
  15.                    "Image 2.png"];
  16.  
  17.  
  18.         APE.Config.transport = 0;
  19.    var client = new APE.Pixelbox('pixelbox','draw', list);
  20. //-->
  21. </script>
  22. <div id="pixelbox">
  23.         <canvas id="draw" width="640" height="480"></canvas>
  24. </div>
  25.  
  1. APE.Pixelbox = new Class({
  2.         Extends: APE.Client,
  3.         //Options//
  4.         apeidentifier: 'pixelbox',
  5.         pixelsize: 10,
  6.         ctx: null,
  7.         els: {},
  8.         pickers: {},
  9.         fcolor: new Color([$random(0,200),$random(0,200),$random(0,200)], 'rgb').hex.substr(1),
  10.         bcolor: '000000',
  11.         mouse: {},
  12.         users: new Hash(),
  13.         tools: new Hash(),
  14.         tool: 'pencil',
  15.         lastPoint: 0,
  16.         grid: null,
  17.         points: [],
  18.         oldSaves: null,
  19.         loaded: 0,
  20.         initialize: function(target,canvas, saves){
  21.                 window.addEvent('domready', this.domReady.bind(this, [target, canvas]));
  22.                 this.oldSaves = saves;
  23.         },
  24.         domReady: function(target, canvas){
  25.  
  26.  
  27.                 this.els.target = $(target);
  28.                 this.els.canvas = $(canvas);
  29.  
  30.                 this.width = this.els.canvas.width / this.pixelsize;
  31.                 this.height = this.els.canvas.height / this.pixelsize;
  32.  
  33.                 this.grid = new Array(this.width * this.height);
  34.  
  35.                 this.ctx = this.els.canvas.getContext('2d');
  36.  
  37.                 this.drawDesign();
  38.  
  39.                 this.addEvent('multiPipeCreate', function(pipe){
  40.                         this.pipe = pipe;
  41.                 }.bind(this));
  42.                 this.onRaw('color_change', this.rawColorChange);
  43.                 this.onRaw('color', this.rawColor);
  44.                 this.onRaw('grid', this.rawGrid);
  45.                 this.onRaw('new_pixelbox_save', this.rawNewSave);
  46.  
  47.                 this.addEvent('userJoin', this.userJoin);
  48.                 this.addEvent('userLeft', this.userLeft);
  49.                 this.addEvent('load', this.loadEv);
  50.                 this.addEvent('ready', this.ready);
  51.                
  52.                 window.addEvent('keypress', this.keyPress.bind(this));
  53.                
  54.                 this.onError('005', this.nickError);//Nick used
  55.                 this.onError('006', this.nickError);//Nick invalid
  56.  
  57.                 this.timer = setInterval(this.tick.bind(this), 20);
  58.  
  59.                 for(var i = 0; i < this.oldSaves.length; i++) {
  60.                         var save = new APE.Pixelbox.Save(this.oldSaves[i]);
  61.                         this.els.gallery.grab(save);
  62.                 }
  63.                
  64.                 this.load({
  65.                         'identifier': this.apeidentifier,
  66.                         'channel':['pixelbox']
  67.                 });
  68.         },
  69.         userJoin: function(user, channel){
  70.                 this.addUser(user.pubid, user.properties.name, user.properties.color);
  71.         },
  72.         userLeft: function(user, channel){
  73.                 var usr = this.users.get(user.pubid);
  74.                 if(usr) {
  75.                         usr.remove();
  76.                         this.users.erase(user.pubid);
  77.                 }
  78.         },
  79.         addUser: function(key, name, color){
  80.                 var user = new APE.Pixelbox.User(name, color);
  81.                 this.users.set(key, user);
  82.                 this.els.users.grab(user);
  83.         },
  84.         drawDesign: function() {
  85.  
  86.                 // Overlay //
  87.                 this.els.overlay = new Element('div', {
  88.                         'class':'overlay'
  89.                 });
  90.                 this.els.popup = {};
  91.                 this.els.popup.main = new Element('div', {
  92.                         'class':'popup'
  93.                 });
  94.  
  95.                 this.els.popup.p = new Element('p', {
  96.                         'class':'ape_name_prompt'
  97.                 });
  98.                 this.els.popup.msg = new Element('span', {
  99.                         'text':'Please choose a nickname: '
  100.                 });
  101.                 this.els.popup.input = new Element('input', {
  102.                         'type':'text',
  103.                         'name':'nick',
  104.                         'autocomplete':'off',
  105.                         'class':'text'
  106.                 });
  107.                 this.els.popup.btn = new Element('button', {
  108.                         'text':'Ok',
  109.                         'class':'submit'
  110.                 });
  111.  
  112.                 this.els.popup.input.addEvent('keydown', function(ev){if(ev.key=='enter'){ this.nickSubmit(ev) }}.bind(this));
  113.                 this.els.popup.btn.addEvent('click', this.nickSubmit.bind(this));
  114.                
  115.                 this.els.popup.p.adopt(this.els.popup.msg, this.els.popup.input, this.els.popup.btn);
  116.                 this.els.popup.main.grab(this.els.popup.p);
  117.  
  118.  
  119.                 this.els.overlay.grab(this.els.popup.main);
  120.  
  121.                 // Main //
  122.                 this.els.canvas.addEvent('mousedown', this.canvasMouse.bind(this));
  123.                 this.els.canvas.addEvent('mouseup', this.canvasMouse.bind(this));
  124.                 this.els.canvas.addEvent('mousemove', this.canvasMouse.bind(this));
  125.  
  126.                 // target //
  127.                 this.els.target.addClass('pixelbox');
  128.  
  129.                 // TOOLS //
  130.  
  131.                 this.els.pencil = new Element('img', {
  132.                         'class':'tool',
  133.                         'alt':'P',
  134.                         'title':'Pencil',
  135.                         'src':'/demos/pixelbox/img/pencil.png'
  136.                 });
  137.                 this.els.pencil.addEvent('click', this.toolClick.bind(this, ['pencil']));
  138.                 this.tools.set('pencil', this.els.pencil);
  139.  
  140.                 this.els.pencil = new Element('img', {
  141.                         'class':'tool',
  142.                         'opacity': 0.5,
  143.                         'alt':'E',
  144.                         'title':'Eye Dropper',
  145.                         'src':'/demos/pixelbox/img/eyedropper.gif'
  146.                 });
  147.                 this.els.pencil.addEvent('click', this.toolClick.bind(this, ['eyedropper']));
  148.                 this.tools.set('eyedropper', this.els.pencil);
  149.  
  150.                 this.els.save = new Element('img', {
  151.                         'class': 'tool',
  152.                         'alt':'Save',
  153.                         'title':'Save image to gallery',
  154.                         'src':'/demos/pixelbox/img/save.png'
  155.                 });
  156.                 this.els.save.addEvent('click', function(){
  157.                         this.pipe.request.send('save_pixelbox');
  158.                 }.bind(this));
  159.  
  160.                 // Gallery //
  161.                 this.els.gallery = new Element('div', {
  162.                         'class':'gallery'
  163.                 });
  164.  
  165.                 // Table //
  166.  
  167.                 this.els.tools = new Element('div', {
  168.                         'class':'tools'
  169.                 });
  170.                 this.els.colors = new Element('div', {
  171.                         'class':'colors'
  172.                 });
  173.                 this.els.fcolor = new Element('div', {
  174.                         'class':'fcolor',
  175.                         'style': 'background-color:  #'+this.fcolor
  176.                 });
  177.                 this.els.bcolor = new Element('div', {
  178.                         'class':'bcolor',
  179.                         'style': 'background-color: #'+this.bcolor
  180.                 });
  181.                 this.els.arrow = new Element('img', {
  182.                         'class':'switch',
  183.                         'src':'/demos/pixelbox/img/switch.png',
  184.                         'alt': 'S'
  185.                 });
  186.                 this.els.arrow.addEvent('click', this.switchColors.bind(this));
  187.                 this.els.colors.adopt(this.els.fcolor, this.els.bcolor, this.els.arrow);
  188.  
  189.                 this.tools.each(function(el){
  190.                         this.els.tools.grab(el);
  191.                 }.bind(this));
  192.  
  193.  
  194.                 this.els.tools.adopt(this.els.save,this.els.colors,this.els.gallery);
  195.  
  196.                 // USERS //
  197.  
  198.                 this.els.users = new Element('div', {
  199.                         'class':'users'
  200.                 });
  201.  
  202.  
  203.                 this.els.target.grab(this.els.tools);
  204.                 this.els.target.grab(this.els.users, 'top');
  205.                 this.els.target.grab(this.els.overlay, 'top');
  206.  
  207.                 // Colors pickers //
  208.                 this.pickers.fcolor = new MooRainbow(this.els.fcolor, {
  209.                         'id':'fcolor',
  210.                         'onChange': this.moorainbowOnChange.bind(this),
  211.                         'onComplete': this.moorainbowOnComplete.bind(this),
  212.                         'startColor': [0,0,0]
  213.                 });
  214.                 this.pickers.bcolor = new MooRainbow(this.els.bcolor, {
  215.                         'id':'bcolor',
  216.                         'onChange': this.moorainbowOnChange.bind(this),
  217.                         'onComplete': this.moorainbowOnComplete.bind(this),
  218.                         'startColor': [255,255,255]
  219.                 });
  220.  
  221.  
  222.                 this.els.popup.input.focus();
  223.         },
  224.         nickError: function(params){
  225.  
  226.                 this.els.popup.input.removeProperty('disabled');
  227.                 this.els.popup.input.set('value', '');
  228.                 this.els.popup.input.focus();
  229.  
  230.                 this.loaded--;
  231.  
  232.                 this.els.popup.msg.set('text', msg);
  233.         },
  234.         loadEv: function(){
  235.                 this.incrementJoin();
  236.         },
  237.         nickSubmit: function(){
  238.                 if(!this.els.popup.input.get('disabled')) {
  239.                         var val = this.els.popup.input.get('value');
  240.                         if(!val) return;
  241.                         else {
  242.                                 this.els.popup.input.set('disabled', 'disabled');
  243.                                 this.nick = val;
  244.                                 this.incrementJoin();
  245.                         }
  246.                 }
  247.         },
  248.         incrementJoin: function(){
  249.                 if(this.core && this.core.options.restore) {
  250.                         this.core.start({}, false);
  251.                         this.core.request.stack.add('restore_pixelbox');
  252.                         this.core.request.stack.send();
  253.                 }else{
  254.                         this.loaded++;
  255.                         if(this.loaded >= 2) {
  256.                                 this.core.start({
  257.                                         'name': this.nick,
  258.                                         'color': this.fcolor
  259.                                 });
  260.                         }
  261.                 }
  262.         },
  263.         ready: function(){//Connected
  264.                 this.els.overlay.set('tween', {duration: 'long'});
  265.                 this.els.overlay.tween('opacity', 0);
  266.  
  267.         },
  268.         moorainbowOnChange: function(color, moor) {
  269.                 moor.element.setStyle('background-color', color.hex);
  270.                 this[moor.options.id] = String(color.hex).substr(1);
  271.         },
  272.         moorainbowOnComplete: function(color, moor) {
  273.                 var clr = String(color.hex).substr(1);
  274.                 this.setColor(moor.options.id, clr);
  275.         },
  276.         rawNewSave: function(params, raw){
  277.                 var save = new APE.Pixelbox.Save(params.data.url+'.png');
  278.                 this.els.gallery.grab(save, 'top');
  279.         },
  280.         tick: function(){
  281.                 var now = this.now();
  282.                 for(var i in this.points) {
  283.                         if(this.points.hasOwnProperty(i)) {
  284.                                 if(this.points[i].when <= now) {
  285.                                         this.drawPoint(this.points[i].pos, this.points[i].color);
  286.                                         delete this.points[i];
  287.                                 }
  288.                         }
  289.                 }
  290.         },
  291.         rawColor: function(params, raw) {
  292.                 var now = this.now();
  293.  
  294.                 var user = this.users.get(params.data.from.pubid);
  295.                 if(user) {
  296.                         user.last = user.last == 0 || now - user.last > 500 ? now : params.data.delay + user.last;
  297.  
  298.                         //console.log('AddPoint at ',user.last);
  299.                         this.points.push({
  300.                                 when: user.last+100,
  301.                                 pos: params.data.pos,
  302.                                 color: params.data.color
  303.                         });
  304.                 }else{
  305.                         this.drawPoint(params.data.pos, params.data.color);
  306.                 }
  307.         },
  308.         rawColorChange: function(params, raw) {
  309.                 var usr = this.users.get(params.data.from.pubid);
  310.                 if(usr){
  311.                         usr.setColor(params.data.color);
  312.                 }
  313.         },
  314.         rawGrid: function(params, raw) {
  315.                 var length = params.data.grid.length;
  316.                 for(var i = 0; i < length; i++){
  317.                         this.drawPoint(i, params.data.grid[i]);
  318.                 }
  319.         },
  320.         setColor: function (type, color){
  321.                 if(type=='fcolor') {
  322.                         if(this.pipe) this.pipe.request.send('color_change', {color:color});
  323.                         this.users.get(this.core.user.pubid).setColor(color);
  324.                 }
  325.                 this[type] = color;
  326.                 this.els[type].setStyle('background-color', '#'+color);
  327.                 this.pickers[type].manualSet('#'+color, 'hex');
  328.         },
  329.         switchColors: function(){
  330.                 var fc = this.fcolor;
  331.                 var bc = this.bcolor;
  332.  
  333.                 this.setColor('fcolor', bc);
  334.                 this.setColor('bcolor', fc);
  335.         },
  336.         keyPress: function(ev){
  337.                 if(ev.key == 'x'){
  338.                         this.switchColors();
  339.                 }
  340.         },
  341.         canvasMouse: function(ev) {
  342.                 if((this.tool == 'eyedropper' || (ev.alt || ev.control)) && ev.type == 'mousedown'){
  343.  
  344.                         var pos = this.mousePos(ev);
  345.  
  346.                         this.setColor('fcolor', this.grid[this.coorToPos(pos.x, pos.y)]);
  347.  
  348.                         this.toolClick('pencil');
  349.  
  350.                 }else if(this.tool == 'pencil') {
  351.                         switch(ev.type){
  352.                                 case 'mousedown':
  353.                                         if(ev.rightClick) return;
  354.                                         var pos = this.mousePos(ev);
  355.                                         if(ev.shift && this.mouse.pos){
  356.                                                 this.drawLine(this.mouse.pos.x,this.mouse.pos.y,pos.x,pos.y);
  357.                                         }
  358.                                         this.mouse.down = true;
  359.                                         this.mouse.pos = pos;
  360.                                         this.drawAtMouse();
  361.                                         break;
  362.                                 case 'mouseup':
  363.                                         if(ev.rightClick) return;
  364.                                         this.mouse.down = false;
  365.                                         break;
  366.                                 case 'mousemove':
  367.                                         if(this.mouse.down){
  368.                                                 var newp = this.mousePos(ev);
  369.                                                 if(this.mouse.pos && !this.comparePoint(newp, this.mouse.pos)){
  370.                                                         this.drawLine(this.mouse.pos.x, this.mouse.pos.y, newp.x, newp.y);
  371.                                                         this.mouse.pos = newp;
  372.                                                         this.drawAtMouse();
  373.                                                 }
  374.                                         }
  375.                                         break;
  376.                         }
  377.                 }
  378.         },
  379.         toolClick: function(tool){
  380.                 if(tool != this.tool) {
  381.  
  382.                         var old_tool = this.tools.get(this.tool);
  383.                         var new_tool = this.tools.get(tool);
  384.                         this.tool = tool;
  385.  
  386.                         old_tool.tween('opacity', 0.5);
  387.                         new_tool.tween('opacity', 1);
  388.                 }
  389.         },
  390.         comparePoint: function(pt1, pt2){
  391.                 return pt1.x == pt2.x && pt1.y == pt2.y;
  392.         },
  393.         mousePos: function(ev){
  394.                 var cp = this.els.canvas.getPosition();
  395.                 var x = Math.floor((ev.page.x - cp.x - 4)/this.pixelsize);
  396.                 var y = Math.floor((ev.page.y - cp.y - 4)/this.pixelsize);
  397.  
  398.                 x = Math.max(x, 0);
  399.                 y = Math.max(y, 0);
  400.  
  401.                 x = Math.min(x, this.width);
  402.                 y = Math.min(y, this.height);
  403.  
  404.                 return {x:x,y:y};
  405.         },
  406.         drawAtMouse: function(){
  407.                 this.sendPixel(this.mouse.pos.x, this.mouse.pos.y, this.fcolor);
  408.         },
  409.         sendPixel: function(x, y, color){
  410.                 color = color || this.fcolor;
  411.                 if(this.pipe){
  412.                         var now = this.now();
  413.  
  414.                         var delay = 0;
  415.                         if(this.lastPoint) delay = now - this.lastPoint;
  416.                         this.lastPoint = now;
  417.  
  418.                         var pos = this.coorToPos(x,y);
  419.                         this.pipe.request.cycledStack.add('color', {pos:pos,color:color,delay:delay});
  420.                         this.drawPoint(pos, color);
  421.                         //this.pipe.request.send('color', {pos:{x:x,y:y},color:color});
  422.                 }
  423.         },
  424.         drawPoint: function(pt, color) {
  425.                 var coor = this.posToCoor(pt);
  426.                 this.drawPixel(coor.x, coor.y, color);
  427.         },
  428.         drawPixel: function(x, y, color){
  429.                 var pos = this.coorToPos(x, y);
  430.                 this.grid[pos] = color;
  431.  
  432.                 this.ctx.fillStyle = '#'+color;
  433.                 this.ctx.fillRect(x*this.pixelsize, y*this.pixelsize, this.pixelsize, this.pixelsize);
  434.         },
  435.         now: function(){
  436.                 var d = new Date();
  437.                 return d.getMilliseconds() + d.getSeconds()*1000 + d.getMinutes()*60*1000 + d.getHours()*60*60*1000;
  438.         },
  439.         coorToPos: function(x, y) {
  440.                 return y*this.width + x;
  441.         },
  442.         posToCoor: function(pos) {
  443.                 return {x:pos%this.width, y:Math.floor(pos/this.width)};
  444.         },
  445.         // Implementation of Bresenham's line algorithm http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
  446.         drawLine: function(x1,y1,x2,y2,drawFirst){
  447.  
  448.                 drawFirst = drawFirst?1:0;
  449.  
  450.                 var dx, dy;
  451.  
  452.                 if( (dx = x2 - x1) != 0 ) {
  453.                         if( dx > 0 ) {
  454.                                 if( (dy = y2 - y1 ) != 0 ) {
  455.                                         if( dy >= 0 ) {// vecteur oblique dans le 1er quadran
  456.  
  457.  
  458.                                                 if( dx >= dy ) {
  459.                                                         // vecteur diagonal ou oblique proche de l’horizontale, dans le 1er octant déclarer entier e ;
  460.                                                         var e;
  461.                                                         dx = (e = dx) * 2; dy *= 2;
  462.                                                         while(true) {
  463.                                                                 if(drawFirst++) this.sendPixel(x1,y1);
  464.                                                                 if( ++x1 == x2 ) break;
  465.                                                                 if( (e -= dy) < 0 ){
  466.                                                                         ++y1;
  467.                                                                         e += dx;
  468.                                                                 }
  469.                                                         }
  470.                                                 } else {
  471.                                                         // vecteur oblique proche de la verticale, dans le 2nd octant
  472.                                                         var e;
  473.                                                         dy = (e = dy) * 2; dx *= 2;
  474.                                                         while(true) {
  475.                                                                 if(drawFirst++) this.sendPixel(x1,y1);
  476.                                                                 if( ++y1 == y2 ) break;
  477.                                                                 if( (e -= dx ) < 0 ){
  478.                                                                         ++x1;
  479.                                                                         e += dy;
  480.                                                                 }
  481.                                                         }
  482.                                                 }
  483.                                         } else {// vecteur oblique dans le 4e cadran
  484.                                                 if(dx >= -dy) { // vecteur diagonal ou oblique proche de l’horizontale, dans le 8e octant
  485.                                                         var e;
  486.                                                         dx = (e = dx) * 2; dy *= 2;
  487.                                                         while(true) {
  488.                                                                 if(drawFirst++) this.sendPixel(x1,y1);
  489.                                                                 if( ++x1 == x2 ) break;
  490.                                                                 if( (e += dy) < 0 ) {
  491.                                                                         --y1;
  492.                                                                         e += dx;
  493.                                                                 }
  494.                                                         }
  495.                                                 } else { // vecteur oblique proche de la verticale, dans le 7e octant
  496.                                                         var e;
  497.                                                         dy = (e = dy) * 2 ; dx *= 2;
  498.                                                         while(true) {
  499.                                                                 if(drawFirst++) this.sendPixel(x1,y1);
  500.                                                                 if( --y1 == y2 ) break;
  501.                                                                 if( (e += dx) > 0) {
  502.                                                                         ++x1;
  503.                                                                         e += dy;
  504.                                                                 }
  505.                                                         }
  506.                                                 }
  507.                                         }
  508.                                 } else { // vecteur horizontal vers la droite
  509.                                         do{
  510.                                                 if(drawFirst++) this.sendPixel(x1,y1);
  511.                                         }while( ++x1 != x2);
  512.                                 }
  513.                         } else { // dx < 0
  514.  
  515.                                 if( (dy = y2 - y1) != 0 ) {
  516.  
  517.                                         if( dy > 0 ) { // vecteur oblique dans le 2nd quadran
  518.                                                
  519.                                                 if( -dx >= dy ) { // vecteur diagonal ou oblique proche de l’horizontale, dans le 4e octant
  520.                                                         var e;
  521.                                                         dx = (e = dx) * 2; dy *= 2;
  522.                                                         while(true) {
  523.                                                                 if(drawFirst++) this.sendPixel(x1,y1);
  524.                                                                 if( --x1 == x2 ) break;
  525.                                                                 if( (e += dy) >= 0 ) {
  526.                                                                         ++y1;
  527.                                                                         e += dx;
  528.                                                                 }
  529.                                                         }
  530.                                                 } else {// vecteur oblique proche de la verticale, dans le 3e octant
  531.                                                         var e;
  532.                                                         dy = (e = dy) * 2; dx *= 2;
  533.                                                         while(true) {
  534.                                                                 if(drawFirst++) this.sendPixel(x1,y1);
  535.                                                                 if( ++y1 == y2) break;
  536.                                                                 if( (e += dx ) <= 0) {
  537.                                                                         --x1;
  538.                                                                         e += dy;
  539.                                                                 }
  540.                                                         }
  541.                                                 }
  542.                                         } else { // vecteur oblique dans le 3e cadran
  543.  
  544.                                                 if( dx <= dy ) { // vecteur diagonal ou oblique proche de l’horizontale, dans le 5e octant
  545.  
  546.                                                         var e;
  547.                                                         dx = (e = dx) * 2; dy *= 2;
  548.                                                         while(true) {
  549.                                                                 if(drawFirst++) this.sendPixel(x1,y1);
  550.                                                                 if(--x1 == x2) break;
  551.                                                                 if( (e -= dy) >= 0) {
  552.                                                                         --y1;
  553.                                                                         e += dx;
  554.                                                                 }
  555.                                                         }
  556.                                                 } else { // vecteur oblique proche de la verticale, dans le 6e octant
  557.                                                         var e;
  558.                                                         dy = (e = dy) *2; dx *= 2;
  559.                                                         while(true) {
  560.                                                                 if(drawFirst++) this.sendPixel(x1,y1);
  561.                                                                 if( --y1 == y2) break;
  562.                                                                 if( (e -= dx) >= 0) {
  563.                                                                         --x1;
  564.                                                                         e += dy;
  565.                                                                 }
  566.                                                         }
  567.                                                 }
  568.                                         }
  569.                                 } else { // vecteur horizontal vers la gauche
  570.                                         do{
  571.                                                 if(drawFirst++) this.sendPixel(x1,y1);
  572.                                         }while(--x1 != x2 );
  573.                                 }
  574.                         }
  575.                 } else {
  576.                         if( (dy = y2 - y1) != 0) {
  577.                                 if( dy > 0) {
  578.                                         do{
  579.                                                 if(drawFirst++) this.sendPixel(x1,y1);
  580.                                         }while( ++y1 != y2 );
  581.                                 } else {
  582.                                         do{
  583.                                                 if(drawFirst++) this.sendPixel(x1,y1);
  584.                                         }while( --y1 != y2);
  585.                                 }
  586.                         }
  587.                 }
  588.         }
  589. });
  590. APE.Pixelbox.User = new Class({
  591.         els: {},
  592.         last: 0,
  593.         initialize: function(login, color){
  594.                 this.els.name = new Element('span', {
  595.                         'class':'nick',
  596.                         'text':login
  597.                 });
  598.                 this.els.color = new Element('span', {
  599.                         'class':'color',
  600.                         'style':'background-color:#'+color
  601.                 });
  602.                 //this.els.color.set('tween', {duration:'long'})
  603.                 this.els.container = new Element('div', {
  604.                         'class':'user'
  605.                 });
  606.                 this.els.container.adopt(this.els.color, this.els.name);
  607.         },
  608.         toElement: function() {
  609.                 return this.els.container;
  610.         },
  611.         setColor: function(clr) {
  612.                 this.els.color.tween('background-color', '#'+clr);
  613.         },
  614.         remove: function() {
  615.                 this.els.container.get('tween').addEvent('complete', function(el){
  616.                         el.destroy();
  617.                 });
  618.                 this.els.container.tween('height', 0);
  619.         }
  620. });
  621. APE.Pixelbox.Save = new Class({
  622.         els: {},
  623.         name: '',
  624.         initialize: function(name){
  625.                 this.name = name;
  626.  
  627.                 this.els.link = new Element('a', {
  628.                         'class':'ReMooz',
  629.                         'href':'/demos/pixelbox/saves/big/'+this.name
  630.                 });
  631.                 this.els.image = new Element('img', {
  632.                         'class':'save',
  633.                         'src': '/demos/pixelbox/saves/small/'+this.name,
  634.                         'alt':'Save'
  635.                 });
  636.                 this.els.link.grab(this.els.image);
  637.                 new ReMooz(this.els.link, {
  638.                         'centered': true,
  639.                         'origin': this.els.image
  640.                 });
  641.         },
  642.         toElement: function() {
  643.                 return this.els.link;
  644.         }
  645. });
  646.  
  1. //
  2. // pixelbox.ape.js
  3. //
  4. include('framework/mootools.js');
  5. include('framework/Http.js');
  6. include('utils/debug.js');
  7.  
  8. var the_channel = 'pixelbox';
  9. var the_width = 64;
  10. var the_height = 48;
  11. var the_grid = new Array(the_width*the_height);
  12.  
  13. var save_url = 'http://example.com/pixelsave.php';
  14.  
  15.  
  16. for(var i = 0; i < the_width*the_height; i++){
  17.         the_grid[i] = 'ffffff';
  18. }
  19.  
  20.  
  21. Ape.addEvent('init', function(){
  22.         //var_export(the_grid);
  23. });
  24. Ape.registerHookCmd("connect", function(params, cmd) {
  25.         if(params.color) {
  26.                 cmd.user.setProperty('color', params.color);
  27.         }else{
  28.                 return {};
  29.         }
  30. });
  31. Ape.addEvent('beforeJoin', function(user, channel){
  32.         /*
  33.         if(channel.getProperty('name') == the_channel){
  34.                 user.setProperty('color', '000');
  35.         }
  36.         */
  37. });
  38. Ape.addEvent('afterJoin', function(user, channel){
  39.         if(channel.getProperty('name') == the_channel) {
  40.                 user.pipe.sendRaw('grid', {grid:the_grid});
  41.         }
  42. });
  43. Ape.registerCmd('restore_pixelbox', true, function(params, infos) {
  44.         infos.user.pipe.sendRaw('grid', {grid:the_grid});
  45. });
  46. Ape.registerCmd('color', true, function(params, infos){
  47.         if(!$defined(params.pos) || !params.color || params.color.length != 6 || params.pos < 0 || params.pos > the_grid.length){
  48.                 Ape.log('Bad params color '+params.color+' - '+params.pos );
  49.                 return 0;
  50.         }
  51.         the_grid[params.pos] = params.color;
  52.        
  53.         Ape.getPipe(params.pipe).sendRaw('color', {pos:params.pos,color:params.color,delay:params.delay}, {from:infos.user.pipe});
  54. });
  55. Ape.registerCmd('save_pixelbox', true, function(params, infos) {
  56.  
  57.         var request = new Http(save_url);
  58.        
  59.         request.set('method', 'POST');
  60.  
  61.         request.writeObject({'pass':'pixelpasswd','img':compress(the_grid) });
  62.        
  63.         request.getContent(imageSaved.bindWithEvent(null, [params.pipe]));
  64. });
  65. function imageSaved(result, pipe){
  66.         Ape.log('Saved :'+result+' - '+pipe);
  67.         if(result != 'ERROR') {
  68.                 var channel = Ape.getPipe(pipe).sendRaw('new_pixelbox_save', {url:result});
  69.         }else{
  70.                 Ape.log('Error while saving image');
  71.         }
  72. }
  73. function compress(ls){
  74.  
  75.         var res = new Array();
  76.         var length = ls.length;
  77.         var size = ls[0].length;
  78.  
  79.         var k = 0;
  80.  
  81.         for(var i=0;i<length;) {
  82.                 Ape.log('looping');
  83.  
  84.                 res[k] = ls[i];
  85.                
  86.                 if(i == length - 1) break;
  87.                
  88.                 var cnt = 1;
  89.  
  90.                 while(ls[++i] == res[k]){
  91.                         //Ape.log('YOOO ' + res[k]);
  92.                         if (!$defined(ls[i])) {
  93.                                 Ape.log('PIXEL SUXXXX');
  94.                         }
  95.                         cnt++;
  96.                 }
  97.  
  98.                 if(cnt > 1) res[k] += String(cnt);
  99.                 ++k;
  100.         }
  101.         return res.join(',');
  102.  
  103. }
  104. Ape.registerCmd('color_change', true, function(params, infos){
  105.         if(!params.color){
  106.                 Ape.log('Bad params color_change');
  107.                 return 0;
  108.         }
  109.         infos.user.setProperty('color', params.color);
  110.         Ape.getPipe(params.pipe).sendRaw('color_change', {'color':params.color}, {from:infos.user.pipe});
  111. });
  112.  
  113. Ape.log('[JS] PixelBox Started !');
  114.  
  115. //
  116. // nickname.js
  117. //
  118.  
  119. var userlist = new $H;
  120.  
  121. Ape.registerHookCmd("connect", function(params, cmd) {
  122.  
  123.         if (!$defined(params.name)) return 0;
  124.         if (userlist.has(params.name.toLowerCase())) return ["005", "NICK_USED"];
  125.         if (params.name.length > 16 || params.name.test('[^a-zA-Z0-9]', 'i')) return ["006", "BAD_NICK"];
  126.  
  127.        
  128.         cmd.user.setProperty('name', params.name);
  129.        
  130.         return 1;
  131. });
  132.  
  133. Ape.addEvent('adduser', function(user) {
  134.         userlist.set(user.getProperty('name').toLowerCase(), true);    
  135. });
  136.  
  137. Ape.addEvent('deluser', function(user) {
  138.         userlist.erase(user.getProperty('name').toLowerCase());
  139. });
  140.