관리 메뉴

HAMA 블로그

Vert.x 를 이용한 실시간 웹 어플리케이션 (4) 본문

Vert.x

Vert.x 를 이용한 실시간 웹 어플리케이션 (4)

[하마] 이승현 (wowlsh93@gmail.com) 2015. 5. 22. 16:01

순서 

1. Vert.x  설치 및 Hello world !! 

2. 간단히  Vert.x  다루어보기 

3..Vert.x 와 MongoDB 연결 

4. 실시간 통신

5. 모듈개발 

6. 배포 



D3 라이브러리를 이용하여 VIEW 를 그릴것이다.  (d3 라이브러리 좀 쩐다... 이거가지고 할수있는거 무궁무진할듯 ) 

http://d3js.org/

http://using.tistory.com/56


1. client.js 부터 살펴보자 

var eb = new vertx.EventBus(window.location.protocol + '//' +

                            window.location.hostname + ':' +

                            window.location.port + '/eventbus');

eb.onopen = function() {

  var renderListItem = function(mindMap) {

    var li = $('<li>');

    var openMindMap = function() {

      new MindMapEditor(mindMap, eb);    //해당 마인드맵이 클릭되면  MindMapEditor 객체를 만든다. 

      return false;                                      

    };                                                        


    var deleteMindMap = function() {

      eb.send('mindMaps.delete', {id: mindMap._id}, function() {

        li.remove();

      });

      return false;

    };

    // 네임클릭하면 마인드맵 활성화됨

    $('<a>').text(mindMap.name).attr('href', '#').on('click', openMindMap).appendTo(li); 

    $('<button>').text('Delete').on('click', deleteMindMap).appendTo(li);


    li.appendTo('.mind-maps');

  };


  $('.create-form').submit(function() {

    var nameInput = $('[name=name]', this);

    eb.send('mindMaps.save', {name: nameInput.val()}, function(result) {

      renderListItem(result);

      nameInput.val('');

    });

    return false;

  });


  eb.send('mindMaps.list', {}, function(res) {  // 서버와 접속되면 마인드맵 리스트를 얻어옵니다. 

    $.each(res.mindMaps, function() {

      renderListItem(this);  // 각 마인드맵을 인자로 넣어주고 리스트 갱신 

    })

  })

};



2. 다음은 editor.js  이거 새로 만들어서 추가해준다. 

function MindMapEditor(mindMap, eventBus) {   /MindMapEditor 생성자

  this.mindMap = mindMap;

  this.eventBus = eventBus;

  this.registerEventHandlers();      // MindMapEditor 객체당 새로운  이벤트핸들러를 등록해준다.

  this.initVisualization();

  this.renderVisualization();

}


MindMapEditor.width = 1280;

MindMapEditor.height = 800;

MindMapEditor.levelWidth = 150;

MindMapEditor.treeLayout = d3.layout.tree().size([MindMapEditor.height, MindMapEditor.width]);

MindMapEditor.diagonalGenerator = d3.svg.diagonal().projection(function(d) { return [d.y, d.x]; });


MindMapEditor.prototype.registerEventHandlers = function() {

  var self = this;

  

  // 이벤트 핸들러를 등록해준다. 나중에 서버에서 발생한 이벤트를 받을수 있게한다. 

  // 상상해본다. 브라우저에서 => 서버 로  Command 날린다.

 //  서버=> 모든 브라우저로  이벤트 전파한다.  이 시스템은 단지 이 두가지로 이루어진다. 

 // 따라서아래의 핸들러는 서버에서 발생한 이벤트를 브라우저에서 적용시키는 과정이다.  

  this.eventBus.registerHandler('mindMaps.events.'+self.mindMap._id, function(event) { 

    switch (event.event) {

      case 'nodeAdded':   self.onNodeAdded(event);   break;

      case 'nodeRenamed': self.onNodeRenamed(event); break;

      case 'nodeDeleted': self.onNodeDeleted(event); break;

    }

    self.renderVisualization();

  });

}


MindMapEditor.prototype.onNodeAdded = function(event) {

  var parent = findNodeByKey(this.mindMap, event.parentKey);

  if (parent) {

  if (!parent.children) {

  parent.children = [];

  }

  parent.children.push(event.node);

  }

}


MindMapEditor.prototype.onNodeRenamed = function(event) {

  var node = findNodeByKey(this.mindMap, event.key);

  if (node) {

  node.name = event.newName;

  }

}


MindMapEditor.prototype.onNodeDeleted = function(event) {

  var parent = findNodeByKey(this.mindMap, event.parentKey);

  if (parent) {

  for (var i=0 ; i<parent.children.length ; i++) {

   if (parent.children[i].key === event.key) {

    parent.children.splice(i, 1);

    return;

   }

  }

  }

}


MindMapEditor.prototype.addNode = function(parentNode) {

  this.eventBus.send('mindMaps.editor.addNode', {

  mindMapId: this.mindMap._id,

  parentKey: parentNode.key

  });

}


MindMapEditor.prototype.renameNode = function(node, newName) {

  this.eventBus.send('mindMaps.editor.renameNode', {

    mindMapId: this.mindMap._id,

    key: node.key,

    newName: newName

  });

}


MindMapEditor.prototype.deleteNode = function(parentNode, childNode) {

  this.eventBus.send('mindMaps.editor.deleteNode', {

    mindMapId: this.mindMap._id,

    parentKey: parentNode.key,

    key: childNode.key

  });

}


MindMapEditor.prototype.initVisualization = function() {

  this.vis = d3.select(".editor").html('').append("svg:svg")

    .attr("width", MindMapEditor.width)

    .attr("height", MindMapEditor.height)

    .append("svg:g")

      .attr("transform", "translate(10,0)");

}


MindMapEditor.prototype.renderVisualization = function() {

  var self = this;

  var nodes = MindMapEditor.treeLayout.nodes(this.mindMap).reverse();

  nodes.forEach(function(d) { d.y = d.depth * MindMapEditor.levelWidth; });

  

  var node = this.vis.selectAll("g.node")

    .data(nodes, function(d) { return d.key; });


  var nodeEnter = node.enter().append("svg:g")

    .attr("class", "node")

    .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })

    .attr("opacity", "0");


  nodeEnter.append("svg:circle")

    .attr("r", 4.5)

    .style("fill", "lightsteelblue")

    .on("click", function(c) { self.addNode(c); });


  nodeEnter.append("svg:text")

    .attr("x", 10)

    .attr("dy", ".35em")

    .text(function(d) { return d.name; })

    .on("click", function(d) {

      var text = prompt('Enter a name for this node', d.name);

      if (text) {

        self.renameNode(d, text);

      }

    });


  node.transition()

    .attr("opacity", "1")

    .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })

    .select("text")

      .text(function(d) { return d.name; });


  node.exit().remove();



  var link = this.vis.selectAll("path.link")

    .data(MindMapEditor.treeLayout.links(nodes), function(d) { return d.target.key; });


  link.enter().insert("svg:path", "g")

    .attr("class", "link")

    .attr("opacity", "0")

    .attr("d", MindMapEditor.diagonalGenerator)

    .on('click', function(l) {

      self.deleteNode(l.source, l.target);

    });


  link.transition()

    .attr("d", MindMapEditor.diagonalGenerator)

    .attr("opacity", "1");


  link.exit().remove();

}



3. mindmap_editor.js 만들어서 추가 

var eventBus = require('vertx/event_bus');
var mindMapUtils = require('web/mindmap_utils');

function newNodeKey() {
  return java.util.UUID.randomUUID().toString();// js 파일에서 자바를 쓸수있는건 vert.x 가 JVM 위에서 돌아감.
}


// 중요 함수다.  위에서 말했다시피 이 시스템의 구조는  브라우저 => 서버 로 Command 실행
//  서버에서 => 모든 브라우저로 이벤트 전파이다. 아래함수는 모든 브라우저(선택된 마인드맵 id 의 핸들러가 등록된)
// 로 이벤트를 전파한다. 
function publishMindMapEvent(mindMap, event) {
  eventBus.publish('mindMaps.events.'+mindMap._id, event);
}

// 브라우저 => 서버로의 Command 를 처리해주는 서버 핸들러
eventBus.registerHandler('mindMaps.editor.addNode', function(args) { 
  eventBus.send('mindMaps.find', {_id: args.mindMapId}, function(res) {
  if (res.mindMap) {
 var mindMap = res.mindMap;
 var parent  = mindMapUtils.findNodeByKey(mindMap, args.parentKey);
 var newNode = {key: newNodeKey()};
 if (args.name) {
newNode.name = args.name;
 } else {
newNode.name = 'Click to edit';
   }

 if (!parent.children) {
parent.children = [];
 }
 parent.children.push(newNode);

 eventBus.send('mindMaps.save', mindMap, function() {
   publishMindMapEvent(mindMap, {event: 'nodeAdded', parentKey: args.parentKey, node: newNode});
 });
    }
  });
});

eventBus.registerHandler('mindMaps.editor.renameNode', function(args) {
  eventBus.send('mindMaps.find', {_id: args.mindMapId}, function(res) {
    if (res.mindMap) {
      var mindMap = res.mindMap;
      var node    = mindMapUtils.findNodeByKey(mindMap, args.key);

      if (node) {
      node.name = args.newName;
      eventBus.send('mindMaps.save', mindMap, function(reply) {
          publishMindMapEvent(mindMap, {event: 'nodeRenamed', key: args.key, newName: args.newName});
      });
      }
    }
  });
});

eventBus.registerHandler('mindMaps.editor.deleteNode', function(args) {
  eventBus.send('mindMaps.find', {_id: args.mindMapId}, function(res) {
    if (res.mindMap) {
      var mindMap = res.mindMap;
      var parent  = mindMapUtils.findNodeByKey(mindMap, args.parentKey);

      parent.children.forEach(function(child, index) {
        if (child.key === args.key) {
          parent.children.splice(index, 1);
          eventBus.send('mindMaps.save', mindMap, function(reply) {
            publishMindMapEvent(mindMap, {event: 'nodeDeleted', parentKey: args.parentKey, key: args.key});
          });
        }
      });
    }
  });
});

실행 모습 




여기까지 대략 프로젝트 구성은 이렇다.




Comments