client/js/paper-renderer.js
changeset 23 70c8af9b44ec
parent 21 b43dd87f7ffa
child 25 b5ada3bb8e53
--- a/client/js/paper-renderer.js	Mon Aug 20 16:07:15 2012 +0200
+++ b/client/js/paper-renderer.js	Tue Aug 21 12:46:11 2012 +0200
@@ -44,7 +44,7 @@
             top: (this._EDITOR_PADDING + _top)
         }
     },
-    sector : function(_ctrl, _inR, _outR, _startAngle, _endAngle, _padding, _imgsrc) {
+    sector : function(_repr, _inR, _outR, _startAngle, _endAngle, _padding, _imgsrc) {
         var _startRads = _startAngle * Math.PI / 180,
             _endRads = _endAngle * Math.PI / 180,
             _img = new Image(),
@@ -94,7 +94,7 @@
         _path.fillColor = "#333333";
         _path.opacity = .5;
         _path.closed = true;
-        _path.__controller = _ctrl;
+        _path.__representation = _repr;
         var _visible = false,
             _restPos = new paper.Point(-200, -200),
             _grp = new paper.Group([_path]),
@@ -142,75 +142,73 @@
     }
 }
 
-Rkns.Renderer._BaseController = function(_renderer, _element) {
+Rkns.Renderer._BaseRepresentation = function(_renderer, _model) {
     if (typeof _renderer !== "undefined") {
-        this.id = Rkns.Utils.getUID('controller');
-        this._renderer = _renderer;
-        this._project = _renderer._project;
-        this._element = _element;
-        this._element.__controller = this;
+        this.renderer = _renderer;
+        this.project = _renderer.renkan.project;
+        this.model = _model;
     }
 }
 
-Rkns.Renderer._BaseController.prototype.select = function() {}
+Rkns.Renderer._BaseRepresentation.prototype.select = function() {}
 
-Rkns.Renderer._BaseController.prototype.unselect = function() {}
+Rkns.Renderer._BaseRepresentation.prototype.unselect = function() {}
 
-Rkns.Renderer._BaseController.prototype.mouseup = function() {}
+Rkns.Renderer._BaseRepresentation.prototype.mouseup = function() {}
 
-Rkns.Renderer._BaseController.prototype.destroy = function() {}
+Rkns.Renderer._BaseRepresentation.prototype.destroy = function() {}
 
-Rkns.Renderer.Node = Rkns.Utils.inherit(Rkns.Renderer._BaseController);
+Rkns.Renderer.Node = Rkns.Utils.inherit(Rkns.Renderer._BaseRepresentation);
 
 Rkns.Renderer.Node.prototype._init = function() {
-    this._renderer.node_layer.activate();
+    this.renderer.node_layer.activate();
     this.type = "Node";
     this.circle = new paper.Path.Circle([0, 0], Rkns._NODE_RADIUS);
     this.circle.fillColor = '#ffffff';
-    this.circle.__controller = this;
+    this.circle.__representation = this;
     this.title = new paper.PointText([0,0]);
     this.title.characterStyle = {
         fontSize: Rkns._NODE_FONT_SIZE,
         fillColor: 'black'
     };
-    this.edit_button = new Rkns.Renderer.NodeEditButton(this._renderer, {});
-    this.edit_button.node_controller = this;
-    this.remove_button = new Rkns.Renderer.NodeRemoveButton(this._renderer, {});
-    this.remove_button.node_controller = this;
-    this.link_button = new Rkns.Renderer.NodeLinkButton(this._renderer, {});
-    this.link_button.node_controller = this;
+    this.edit_button = new Rkns.Renderer.NodeEditButton(this.renderer, {});
+    this.edit_button.node_representation = this;
+    this.remove_button = new Rkns.Renderer.NodeRemoveButton(this.renderer, {});
+    this.remove_button.node_representation = this;
+    this.link_button = new Rkns.Renderer.NodeLinkButton(this.renderer, {});
+    this.link_button.node_representation = this;
     this.title.paragraphStyle.justification = 'center';
-    this.title.__controller = this;
+    this.title.__representation = this;
 }
 
 Rkns.Renderer.Node.prototype.redraw = function() {
-    var _model_coords = new paper.Point(this._element.position);
-    this.paper_coords = this._renderer.toPaperCoords(_model_coords);
+    var _model_coords = new paper.Point(this.model.get("position"));
+    this.paper_coords = this.renderer.toPaperCoords(_model_coords);
     this.circle.position = this.paper_coords;
-    this.title.content = this._element.title;
+    this.title.content = this.model.get("title");
     this.title.position = this.paper_coords.add([0, 2 * Rkns._NODE_RADIUS]);
-    this.circle.strokeColor = this._element.created_by.color;
+    this.circle.strokeColor = this.model.get("created_by").get("color");
     this.edit_button.moveTo(this.paper_coords);
     this.remove_button.moveTo(this.paper_coords);
     this.link_button.moveTo(this.paper_coords);
 }
 
 Rkns.Renderer.Node.prototype.paperShift = function(_delta) {
-    var _coords = this._renderer.toModelCoords(this.paper_coords.add(_delta)),
+    var _coords = this.renderer.toModelCoords(this.paper_coords.add(_delta)),
         _data = {
             position: {
                 x: _coords.x,
                 y: _coords.y
             }
         };
-    this._project.updateElement(this.type, this._element, _data, Rkns._SAVE);
-    this._renderer.redraw();
+    this.model.set(_data);
+    this.renderer.redraw();
 }
 
 Rkns.Renderer.Node.prototype.openEditor = function() {
-    this._renderer.removeControllersOfType("editor");
-    var _editor = this._renderer.addController("NodeEditor",{});
-    _editor.node_controller = this;
+    this.renderer.removeRepresentationsOfType("editor");
+    var _editor = this.renderer.addRepresentation("NodeEditor",null);
+    _editor.node_representation = this;
     _editor.redraw();
 }
 
@@ -231,7 +229,7 @@
 }
 
 Rkns.Renderer.Node.prototype.mouseup = function(_event) {
-    if (!this._renderer.is_dragging) {
+    if (!this.renderer.is_dragging) {
         this.openEditor();
     }
 }
@@ -245,37 +243,37 @@
 
 /* */
 
-Rkns.Renderer.Edge = Rkns.Utils.inherit(Rkns.Renderer._BaseController);
+Rkns.Renderer.Edge = Rkns.Utils.inherit(Rkns.Renderer._BaseRepresentation);
 
 Rkns.Renderer.Edge.prototype._init = function() {
-    this._renderer.edge_layer.activate();
+    this.renderer.edge_layer.activate();
     this.type = "Edge";
-    this.from_controller = this._element.from.__controller;
-    this.to_node_controller = this._element.to.__controller;
+    this.from_representation = this.renderer.getRepresentationByModel(this.model.get("from"));
+    this.to_representation = this.renderer.getRepresentationByModel(this.model.get("to"));
     this.line = new paper.Path();
     this.line.add([0,0],[0,0]);
-    this.line.__controller = this;
+    this.line.__representation = this;
     this.arrow = new paper.Path();
     this.arrow.add([0,0],[Rkns._ARROW_LENGTH,Rkns._ARROW_WIDTH / 2],[0,Rkns._ARROW_WIDTH]);
-    this.arrow.__controller = this;
+    this.arrow.__representation = this;
     this.text = new paper.PointText();
     this.text.characterStyle = {
         fontSize: Rkns._EDGE_FONT_SIZE,
         fillColor: 'black'
     };
     this.text.paragraphStyle.justification = 'center';
-    this.text.__controller = this;
+    this.text.__representation = this;
     this.text_angle = 0;
     this.arrow_angle = 0;
-    this.edit_button = new Rkns.Renderer.EdgeEditButton(this._renderer, {});
-    this.edit_button.edge_controller = this;
-    this.remove_button = new Rkns.Renderer.EdgeRemoveButton(this._renderer, {});
-    this.remove_button.edge_controller = this;
+    this.edit_button = new Rkns.Renderer.EdgeEditButton(this.renderer, {});
+    this.edit_button.edge_representation = this;
+    this.remove_button = new Rkns.Renderer.EdgeRemoveButton(this.renderer, {});
+    this.remove_button.edge_representation = this;
 }
 
 Rkns.Renderer.Edge.prototype.redraw = function() {
-    var _p0o = this.from_controller.paper_coords,
-        _p1o = this.to_node_controller.paper_coords,
+    var _p0o = this.from_representation.paper_coords,
+        _p1o = this.to_representation.paper_coords,
         _v = _p1o.subtract(_p0o),
         _r = _v.length,
         _u = _v.divide(_r),
@@ -283,7 +281,7 @@
         _p0 = _p0o.add(_delta), /* Adding a 4 px difference */
         _p1 = _p1o.add(_delta), /* to differentiate inbound and outbound links */
         _a = _v.angle,
-        _color = this._element.created_by.color;
+        _color = this.model.get("created_by").get("color");
     this.paper_coords = _p0.add(_p1).divide(2);
     this.line.strokeColor = _color;
     this.line.segments[0].point = _p0;
@@ -299,7 +297,7 @@
         _a += 180;
     }
     this.text.rotate(_a - this.text_angle);
-    this.text.content = this._element.title;
+    this.text.content = this.model.get("title");
     this.text.position = this.paper_coords;
     this.text_angle = _a;
     this.edit_button.moveTo(this.paper_coords);
@@ -307,9 +305,9 @@
 }
 
 Rkns.Renderer.Edge.prototype.openEditor = function() {
-    this._renderer.removeControllersOfType("editor");
-    var _editor = this._renderer.addController("EdgeEditor",{});
-    _editor.edge_controller = this;
+    this.renderer.removeRepresentationsOfType("editor");
+    var _editor = this.renderer.addRepresentation("EdgeEditor",null);
+    _editor.edge_representation = this;
     _editor.redraw();
 }
 
@@ -328,15 +326,15 @@
 }
 
 Rkns.Renderer.Edge.prototype.mouseup = function(_event) {
-    if (!this._renderer.is_dragging) {
+    if (!this.renderer.is_dragging) {
         this.openEditor();
     }
 }
 
 Rkns.Renderer.Edge.prototype.paperShift = function(_delta) {
-    this.from_controller.paperShift(_delta);
-    this.to_node_controller.paperShift(_delta);
-    this._renderer.redraw();
+    this.from_representation.paperShift(_delta);
+    this.to_representation.paperShift(_delta);
+    this.renderer.redraw();
 }
 
 Rkns.Renderer.Edge.prototype.destroy = function() {
@@ -349,25 +347,26 @@
 
 /* */
 
-Rkns.Renderer.TempEdge = Rkns.Utils.inherit(Rkns.Renderer._BaseController);
+Rkns.Renderer.TempEdge = Rkns.Utils.inherit(Rkns.Renderer._BaseRepresentation);
 
 Rkns.Renderer.TempEdge.prototype._init = function() {
-    this._renderer.edge_layer.activate();
+    this.renderer.edge_layer.activate();
     this.type = "temp-edge";
-    var _color = this._project.current_user.color;
+    
+    var _color = this.project.get("users").get(this.renderer.renkan.current_user).get("color");
     this.line = new paper.Path();
     this.line.strokeColor = _color;
     this.line.add([0,0],[0,0]);
-    this.line.__controller = this;
+    this.line.__representation = this;
     this.arrow = new paper.Path();
     this.arrow.fillColor = _color;
     this.arrow.add([0,0],[Rkns._ARROW_LENGTH,Rkns._ARROW_WIDTH / 2],[0,Rkns._ARROW_WIDTH]);
-    this.arrow.__controller = this;
+    this.arrow.__representation = this;
     this.arrow_angle = 0;
 }
 
 Rkns.Renderer.TempEdge.prototype.redraw = function() {
-    var _p0 = this.from_controller.paper_coords,
+    var _p0 = this.from_representation.paper_coords,
         _p1 = this.end_pos,
         _a = _p1.subtract(_p0).angle,
         _c = _p0.add(_p1).divide(2);
@@ -381,22 +380,25 @@
 Rkns.Renderer.TempEdge.prototype.paperShift = function(_delta) {
     this.end_pos = this.end_pos.add(_delta);
     var _hitResult = paper.project.hitTest(this.end_pos);
-    this._renderer.findTarget(_hitResult);
+    this.renderer.findTarget(_hitResult);
     this.redraw();
 }
 
 Rkns.Renderer.TempEdge.prototype.mouseup = function(_event) {
     var _hitResult = paper.project.hitTest(_event.point);
-    if (_hitResult && typeof _hitResult.item.__controller !== "undefined") {
-        var _target = _hitResult.item.__controller;
-        if (_target.type === "Node" && this.from_controller._element.id !== _target._element.id) {
-            this._project.addEdge({
-                from: this.from_controller._element.id,
-                to: _target._element.id
-            }, Rkns._RENDER_AND_SAVE)
+    if (_hitResult && typeof _hitResult.item.__representation !== "undefined") {
+        var _target = _hitResult.item.__representation;
+        if (_target.type === "Node" && this.from_representation.model !== _target.model) {
+            var _data = {
+                id: Rkns.Utils.getUID('edge'),
+                created_by: this.renderer.renkan.current_user,
+                from: this.from_representation.model.get("id"),
+                to: _target.model.get("id")
+            };
+            this.project.addEdge(_data);
         }
     }
-    this._renderer.removeController(this);
+    this.renderer.removeRepresentation(this);
 }
 
 Rkns.Renderer.TempEdge.prototype.destroy = function() {
@@ -406,10 +408,10 @@
 
 /* */
 
-Rkns.Renderer.NodeEditor = Rkns.Utils.inherit(Rkns.Renderer._BaseController);
+Rkns.Renderer.NodeEditor = Rkns.Utils.inherit(Rkns.Renderer._BaseRepresentation);
 
 Rkns.Renderer.NodeEditor.prototype._init = function() {
-    this._renderer.overlay_layer.activate();
+    this.renderer.overlay_layer.activate();
     this.type = "editor";
     this.editor_block = new paper.Path();
     var _pts = Rkns._(Rkns._.range(8)).map(function() {return [0,0]});
@@ -419,7 +421,7 @@
     this.editor_block.fillColor = "#e0e0e0";
     this.editor_block.opacity = .8;
     this.editor_$ = Rkns.$('<div>')
-        .appendTo(this._renderer.editor_$)
+        .appendTo(this.renderer.editor_$)
         .css({
             position: "absolute",
             opacity: .8
@@ -436,19 +438,27 @@
 );
 
 Rkns.Renderer.NodeEditor.prototype.redraw = function() {
-    var _coords = this.node_controller.paper_coords,
-        _element = this.node_controller._element,
+    var _coords = this.node_representation.paper_coords,
+        _model = this.node_representation.model,
         _css = Rkns.Renderer.Utils.drawEditBox(_coords, this.editor_block, 250, 300);
     this.editor_$
         .html(this.template({
-            node: _element,
-            l10n: this._project.l10n
+            node: {
+                title: _model.get("title"),
+                uri: _model.get("uri"),
+                description: _model.get("description"),
+                created_by: {
+                    color: _model.get("created_by").get("color"),
+                    title: _model.get("created_by").get("title")
+                }
+            },
+            l10n: this.renderer.renkan.l10n
         }))
         .show()
         .css(_css);
     var _this = this;
     this.editor_$.find(".Rk-CloseX").click(function() {
-        _this._renderer.removeController(_this);
+        _this.renderer.removeRepresentation(_this);
         paper.view.draw();
     });
     this.editor_$.find("input, textarea").bind("keyup change", function() {
@@ -457,15 +467,11 @@
             description: _this.editor_$.find(".Rk-Edit-Description").val(),
             uri: _this.editor_$.find(".Rk-Edit-URI").val()
         }
-        _this._project.updateNode(
-            _element,
-            _data,
-            Rkns._SAVE
-        );
-        _this.node_controller.redraw();
+        _model.set(_data);
         paper.view.draw();
     });
     this.editor_$.find(".Rk-Edit-Title")[0].focus();
+    paper.view.draw();
 }
 
 Rkns.Renderer.NodeEditor.prototype.destroy = function() {
@@ -475,10 +481,10 @@
 
 /* */
 
-Rkns.Renderer.EdgeEditor = Rkns.Utils.inherit(Rkns.Renderer._BaseController);
+Rkns.Renderer.EdgeEditor = Rkns.Utils.inherit(Rkns.Renderer._BaseRepresentation);
 
 Rkns.Renderer.EdgeEditor.prototype._init = function() {
-    this._renderer.overlay_layer.activate();
+    this.renderer.overlay_layer.activate();
     this.type = "editor";
     this.editor_block = new paper.Path();
     var _pts = Rkns._(Rkns._.range(8)).map(function() {return [0,0]});
@@ -488,7 +494,7 @@
     this.editor_block.fillColor = "#e0e0e0";
     this.editor_block.opacity = .8;
     this.editor_$ = Rkns.$('<div>')
-        .appendTo(this._renderer.editor_$)
+        .appendTo(this.renderer.editor_$)
         .css({
             position: "absolute",
             opacity: .8
@@ -506,19 +512,19 @@
 );
 
 Rkns.Renderer.EdgeEditor.prototype.redraw = function() {
-    var _coords = this.edge_controller.paper_coords,
-        _element = this.edge_controller._element,
+    var _coords = this.edge_representation.paper_coords,
+        _model = this.edge_representation.model,
         _css = Rkns.Renderer.Utils.drawEditBox(_coords, this.editor_block, 250, 200);
     this.editor_$
         .html(this.template({
-            edge: _element,
-            l10n: this._project.l10n
+            edge: _model,
+            l10n: this.renderer.renkan.l10n
         }))
         .show()
         .css(_css);
     var _this = this;
     this.editor_$.find(".Rk-CloseX").click(function() {
-        _this._renderer.removeController(_this);
+        _this.renderer.removeRepresentation(_this);
         paper.view.draw();
     });
     this.editor_$.find("input, textarea").bind("keyup change", function() {
@@ -526,14 +532,10 @@
             title: _this.editor_$.find(".Rk-Edit-Title").val(),
             uri: _this.editor_$.find(".Rk-Edit-URI").val()
         }
-        _this._project.updateEdge(
-            _element,
-            _data,
-            Rkns._SAVE
-        );
-        _this.edge_controller.redraw();
+        _model.set(_data);
         paper.view.draw();
     });
+    paper.view.draw();
 }
 
 Rkns.Renderer.EdgeEditor.prototype.destroy = function() {
@@ -543,10 +545,10 @@
 
 /* */
 
-Rkns.Renderer.NodeEditButton = Rkns.Utils.inherit(Rkns.Renderer._BaseController);
+Rkns.Renderer.NodeEditButton = Rkns.Utils.inherit(Rkns.Renderer._BaseRepresentation);
 
 Rkns.Renderer.NodeEditButton.prototype._init = function() {
-    this._renderer.node_layer.activate();
+    this.renderer.node_layer.activate();
     this.type = "Node-edit-button";
     this.sector = Rkns.Renderer.Utils.sector(this, 1 + Rkns._NODE_RADIUS, 3 * Rkns._NODE_RADIUS, - 90, 30, 2, 'img/edit.png');
 }
@@ -570,13 +572,13 @@
 Rkns.Renderer.NodeEditButton.prototype.unselect = function() {
     this.sector.unselect();
     this.hide();
-    this.node_controller.remove_button.hide();
-    this.node_controller.link_button.hide();
+    this.node_representation.remove_button.hide();
+    this.node_representation.link_button.hide();
 }
 
 Rkns.Renderer.NodeEditButton.prototype.mouseup = function() {
-    if (!this._renderer.is_dragging) {
-        this.node_controller.openEditor();
+    if (!this.renderer.is_dragging) {
+        this.node_representation.openEditor();
     }
 }
 
@@ -586,10 +588,10 @@
 
 /* */
 
-Rkns.Renderer.NodeRemoveButton = Rkns.Utils.inherit(Rkns.Renderer._BaseController);
+Rkns.Renderer.NodeRemoveButton = Rkns.Utils.inherit(Rkns.Renderer._BaseRepresentation);
 
 Rkns.Renderer.NodeRemoveButton.prototype._init = function() {
-    this._renderer.node_layer.activate();
+    this.renderer.node_layer.activate();
     this.type = "Node-remove-button";
     this.sector = Rkns.Renderer.Utils.sector(this, 1 + Rkns._NODE_RADIUS, 3 * Rkns._NODE_RADIUS, -210, -90, 2, 'img/remove.png');
 }
@@ -613,13 +615,13 @@
 Rkns.Renderer.NodeRemoveButton.prototype.unselect = function() {
     this.sector.unselect();
     this.hide();
-    this.node_controller.edit_button.hide();
-    this.node_controller.link_button.hide();
+    this.node_representation.edit_button.hide();
+    this.node_representation.link_button.hide();
 }
 
 Rkns.Renderer.NodeRemoveButton.prototype.mouseup = function() {
-    if (confirm('Do you really wish to remove node "' + this.node_controller._element.title + '"?')) {
-        this._renderer._project.removeNode(this.node_controller._element, Rkns._RENDER_AND_SAVE);
+    if (confirm('Do you really wish to remove node "' + this.node_representation.model.get("title") + '"?')) {
+        this.project.removeNode(this.node_representation.model);
     }
 }
 
@@ -629,10 +631,10 @@
 
 /* */
 
-Rkns.Renderer.NodeLinkButton = Rkns.Utils.inherit(Rkns.Renderer._BaseController);
+Rkns.Renderer.NodeLinkButton = Rkns.Utils.inherit(Rkns.Renderer._BaseRepresentation);
 
 Rkns.Renderer.NodeLinkButton.prototype._init = function() {
-    this._renderer.node_layer.activate();
+    this.renderer.node_layer.activate();
     this.type = "Node-link-button";
     this.sector = Rkns.Renderer.Utils.sector(this, 1 + Rkns._NODE_RADIUS , 3 * Rkns._NODE_RADIUS, 30, 150, 2, 'img/link.png');
 }
@@ -656,8 +658,8 @@
 Rkns.Renderer.NodeLinkButton.prototype.unselect = function() {
     this.sector.unselect();
     this.hide();
-    this.node_controller.edit_button.hide();
-    this.node_controller.remove_button.hide();
+    this.node_representation.edit_button.hide();
+    this.node_representation.remove_button.hide();
 }
 
 Rkns.Renderer.NodeLinkButton.prototype.destroy = function() {
@@ -666,10 +668,10 @@
 
 /* */
 
-Rkns.Renderer.EdgeEditButton = Rkns.Utils.inherit(Rkns.Renderer._BaseController);
+Rkns.Renderer.EdgeEditButton = Rkns.Utils.inherit(Rkns.Renderer._BaseRepresentation);
 
 Rkns.Renderer.EdgeEditButton.prototype._init = function() {
-    this._renderer.edge_layer.activate();
+    this.renderer.edge_layer.activate();
     this.type = "Edge-edit-button";
     this.sector = Rkns.Renderer.Utils.sector(this, 5 , 2 * Rkns._NODE_RADIUS, - 60, 60, 2, 'img/edit.png');
 }
@@ -693,12 +695,12 @@
 Rkns.Renderer.EdgeEditButton.prototype.unselect = function() {
     this.sector.unselect();
     this.hide();
-    this.edge_controller.remove_button.hide();
+    this.edge_representation.remove_button.hide();
 }
 
 Rkns.Renderer.EdgeEditButton.prototype.mouseup = function() {
-    if (!this._renderer.is_dragging) {
-        this.edge_controller.openEditor();
+    if (!this.renderer.is_dragging) {
+        this.edge_representation.openEditor();
     }
 }
 
@@ -708,10 +710,10 @@
 
 /* */
 
-Rkns.Renderer.EdgeRemoveButton = Rkns.Utils.inherit(Rkns.Renderer._BaseController);
+Rkns.Renderer.EdgeRemoveButton = Rkns.Utils.inherit(Rkns.Renderer._BaseRepresentation);
 
 Rkns.Renderer.EdgeRemoveButton.prototype._init = function() {
-    this._renderer.edge_layer.activate();
+    this.renderer.edge_layer.activate();
     this.type = "Edge-remove-button";
     this.sector = Rkns.Renderer.Utils.sector(this, 5, 2 * Rkns._NODE_RADIUS, - 240, -120, 2, 'img/remove.png');
 }
@@ -734,12 +736,12 @@
 Rkns.Renderer.EdgeRemoveButton.prototype.unselect = function() {
     this.sector.unselect();
     this.hide();
-    this.edge_controller.edit_button.hide();
+    this.edge_representation.edit_button.hide();
 }
 
 Rkns.Renderer.EdgeRemoveButton.prototype.mouseup = function() {
-    if (confirm('Do you really wish to remove edge "' + this.edge_controller._element.title + '"?')) {
-        this._renderer._project.removeEdge(this.edge_controller._element, Rkns._RENDER_AND_SAVE);
+    if (confirm('Do you really wish to remove edge "' + this.edge_representation.model.get("title") + '"?')) {
+        this.project.removeEdge(this.edge_representation.model);
     }
 }
 
@@ -749,13 +751,14 @@
 
 /* */
 
-Rkns.Renderer.Scene = function(_project) {
-    this._project = _project;
+Rkns.Renderer.Scene = function(_renkan) {
+    this.renkan = _renkan;
     this._MARGIN_X = 80;
     this._MARGIN_Y = 50;
     this.$ = Rkns.$(".Rk-Render");
+    this.representations = [];
     this.$.html(this.template({
-        l10n: this._project.l10n
+        l10n: _renkan.l10n
     }))
     this.canvas_$ = this.$.find(".Rk-Canvas");
     this.editor_$ = this.$.find(".Rk-Editor");
@@ -812,6 +815,24 @@
         _this.offset = _this.offset.add(_event.delta.divide(2));
         _this.redraw();
     }
+    
+    var _thRedraw = Rkns._.throttle(function() {
+        _this.redraw();
+    },50);
+    
+    this.addRepresentations("Node", this.renkan.project.get("nodes"));
+    this.addRepresentations("Edge", this.renkan.project.get("edges"));
+    
+    this.renkan.project.on("add:nodes", function(_node) {
+        _this.addRepresentation("Node", _node);
+        _thRedraw();
+    });
+    this.renkan.project.on("add:edges", function(_edge) {
+        _this.addRepresentation("Edge", _edge);
+        _thRedraw();
+    });
+    
+    this.redraw();
 }
 
 Rkns.Renderer.Scene.prototype.template = Rkns._.template(
@@ -829,67 +850,73 @@
     return _point.subtract(this.offset).divide(this.scale);
 }
 
-Rkns.Renderer.Scene.prototype.draw = function() {
-    var _this = this,
-        _xx = this._project.nodes.map(function(_node) { return _node.position.x }),
-        _yy = this._project.nodes.map(function(_node) { return _node.position.y }),
-        _minx = Math.min.apply(Math, _xx),
-        _miny = Math.min.apply(Math, _yy),
-        _maxx = Math.max.apply(Math, _xx),
-        _maxy = Math.max.apply(Math, _yy);
-    this.scale = Math.min((paper.view.size.width - 2 * this._MARGIN_X) / (_maxx - _minx), (paper.view.size.height - 2 * this._MARGIN_Y) / (_maxy - _miny));
-    this.offset = paper.view.center.subtract(new paper.Point([(_maxx + _minx) / 2, (_maxy + _miny) / 2]).multiply(this.scale));
-    this.controllers = new Rkns.ViewModel.List();
-    this._project.nodes.forEach(function(_node) {
-        _this.addController("Node", _node);
+Rkns.Renderer.Scene.prototype.addRepresentation = function(_type, _model) {
+    var _repr = new Rkns.Renderer[_type](this, _model);
+    this.representations.push(_repr);
+    if (_model) {
+        var _this = this;
+        _model.on("change", function() {
+            _repr.redraw();
+        });
+        _model.on("remove", function() {
+            _this.removeRepresentation(_repr);
+            _this.redraw();
+        });
+    }
+    return _repr;
+}
+
+Rkns.Renderer.Scene.prototype.addRepresentations = function(_type, _collection) {
+    var _this = this;
+    _collection.forEach(function(_model) {
+        _this.addRepresentation(_type, _model);
     });
-    this._project.edges.forEach(function(_edge) {
-        _this.addController("Edge", _edge);
-    });
-    
-    this.redraw();
 }
 
-Rkns.Renderer.Scene.prototype.addController = function(_type, _controller) {
-    var _el = new Rkns.Renderer[_type](this, _controller);
-    this.controllers.push(_el);
-    return _el;
+Rkns.Renderer.Scene.prototype.removeRepresentation = function(_representation) {
+    _representation.destroy();
+    this.representations = Rkns._(this.representations).reject(
+        function(_repr) {
+            return _repr == _representation
+        }
+    );
 }
 
-Rkns.Renderer.Scene.prototype.removeController = function(_controller) {
-    _controller.destroy();
-    this.controllers.removeId(_controller.id);
+Rkns.Renderer.Scene.prototype.getRepresentationByModel = function(_model) {
+    return Rkns._(this.representations).find(function(_repr) {
+        return _repr.model === _model;
+    });
 }
 
-Rkns.Renderer.Scene.prototype.removeControllersOfType = function(_type) {
-    var _controllers = this.controllers.filter(function(_ctrl) {
-            return _ctrl.type == _type;
+Rkns.Renderer.Scene.prototype.removeRepresentationsOfType = function(_type) {
+    var _representations = Rkns._(this.representations).filter(function(_repr) {
+            return _repr.type == _type;
         }),
         _this = this;
-    _controllers.forEach(function(_ctrl) {
-        _this.removeController(_ctrl);
+    Rkns._(_representations).each(function(_repr) {
+        _this.removeRepresentation(_repr);
     });
 }
 
 Rkns.Renderer.Scene.prototype.redraw = function() {
-    this.controllers.forEach(function(_controller) {
-        _controller.redraw();
+    Rkns._(this.representations).each(function(_representation) {
+        _representation.redraw();
     });
     paper.view.draw();
 }
 
 Rkns.Renderer.Scene.prototype.addTempEdge = function(_from, _point) {
-    var _tmpEdge = this.addController("TempEdge",{});
+    var _tmpEdge = this.addRepresentation("TempEdge",null);
     _tmpEdge.end_pos = _point;
-    _tmpEdge.from_controller = _from;
+    _tmpEdge.from_representation = _from;
     _tmpEdge.redraw();
     this.click_target = _tmpEdge;
 }
 
 Rkns.Renderer.Scene.prototype.findTarget = function(_hitResult) {
-    if (_hitResult && typeof _hitResult.item.__controller !== "undefined") {
-        var _newTarget = _hitResult.item.__controller;
-        if (this.selected_target !== _hitResult.item.__controller) {
+    if (_hitResult && typeof _hitResult.item.__representation !== "undefined") {
+        var _newTarget = _hitResult.item.__representation;
+        if (this.selected_target !== _hitResult.item.__representation) {
             if (this.selected_target) {
                 this.selected_target.unselect(_newTarget);
             }
@@ -921,13 +948,13 @@
 Rkns.Renderer.Scene.prototype.onMouseDown = function(_event) {
     this.is_dragging = false;
     var _hitResult = paper.project.hitTest(_event.point);
-    if (_hitResult && typeof _hitResult.item.__controller !== "undefined") {
-        this.click_target = _hitResult.item.__controller;
+    if (_hitResult && typeof _hitResult.item.__representation !== "undefined") {
+        this.click_target = _hitResult.item.__representation;
         if (this.click_target.type === "Node" && _hitResult.type === "stroke") {
             this.addTempEdge(this.click_target, _event.point);
         }
         if (this.click_target.type === "Node-link-button") {
-            this.addTempEdge(this.click_target.node_controller, _event.point);
+            this.addTempEdge(this.click_target.node_representation, _event.point);
         }
     } else {
         this.click_target = null;
@@ -982,15 +1009,18 @@
             _event.pageY - _off.top
         ]);
     var _hitResult = paper.project.hitTest(_point);
-    if (!_hitResult || typeof _hitResult.item.__controller === "undefined") {
+    if (!_hitResult || typeof _hitResult.item.__representation === "undefined") {
         var _coords = this.toModelCoords(_point),
-            _node = this._project.addNode({
+            _data = {
+                id: Rkns.Utils.getUID('node'),
+                created_by: this.renkan.current_user,
                 position: {
                     x: _coords.x,
                     y: _coords.y
                 }
-            }, Rkns._RENDER_AND_SAVE);
-        _node.__controller.openEditor();
+            };
+            _node = this.renkan.project.addNode(_data);
+            this.getRepresentationByModel(_node).openEditor();
     }
     paper.view.draw();
 }
@@ -1004,7 +1034,9 @@
                 _event.pageY - _off.top
             ]),
             _coords = this.toModelCoords(_point),
-            _node = this._project.addNode({
+            _data = {
+                id: Rkns.Utils.getUID('node'),
+                created_by: this.renkan.current_user,
                 uri: _newEl.uri,
                 title: _newEl.title,
                 description: _newEl.description,
@@ -1012,8 +1044,10 @@
                     x: _coords.x,
                     y: _coords.y
                 }
-            }, Rkns._RENDER_AND_SAVE);
+            };
+        var _node = this.renkan.project.addNode(_data);
+        this.renkan.selected_bin_item = null;
         this.is_dragging = true;
-        this.click_target = _node.__controller;
+        this.click_target = this.getRepresentationByModel(_node);
     }
 }
\ No newline at end of file