client/js/paper-renderer.js
changeset 120 112a82ddd7e5
parent 119 0f7d2275a88f
child 122 ea11e17e0a35
equal deleted inserted replaced
119:0f7d2275a88f 120:112a82ddd7e5
     1 Rkns.Renderer = {
     1 Rkns.Renderer = {
     2     _MINIMAP_MARGIN_X: 20,
     2     _MINIMAP_MARGIN: 20,
     3     _MINIMAP_MARGIN_Y: 20,
       
     4     _MIN_DRAG_DISTANCE: 2,
     3     _MIN_DRAG_DISTANCE: 2,
     5     _NODE_SIZE_BASE: 25,
     4     _NODE_SIZE_BASE: 25,
     6     _NODE_BUTTON_WIDTH: 40,
     5     _NODE_BUTTON_WIDTH: 40,
     7     _EDGE_BUTTON_INNER: 2,
     6     _EDGE_BUTTON_INNER: 2,
     8     _EDGE_BUTTON_OUTER: 40,
     7     _EDGE_BUTTON_OUTER: 40,
     9     _NODE_FONT_SIZE: 10,
       
    10     _EDGE_FONT_SIZE: 9,
       
    11     _EDGE_DISTANCE: 3,
       
    12     _NODE_MAX_CHAR: 50,
       
    13     _EDGE_MAX_CHAR: 40,
       
    14     _ARROW_LENGTH: 18,
       
    15     _ARROW_WIDTH: 12,
       
    16     _EDITOR_ARROW_LENGTH : 20,
       
    17     _EDITOR_ARROW_WIDTH : 40,
       
    18     _EDITOR_WIDTH : 275,
       
    19     _EDITOR_MARGIN : 15,
       
    20     _EDITOR_PADDING : 10,
       
    21     _EDITOR_GRADIENT : new paper.Gradient(['#f0f0f0', '#d0d0d0']),
       
    22     _CLICKMODE_ADDNODE : 1,
     8     _CLICKMODE_ADDNODE : 1,
    23     _CLICKMODE_STARTEDGE : 2,
     9     _CLICKMODE_STARTEDGE : 2,
    24     _CLICKMODE_ENDEDGE : 3,
    10     _CLICKMODE_ENDEDGE : 3,
    25     _IMAGE_MAX_KB : 500,
    11     _IMAGE_MAX_KB : 500,
    26     _NODE_SIZE_STEP: Math.LN2/4,
    12     _NODE_SIZE_STEP: Math.LN2/4,
       
    13     _MIN_SCALE: 1/20,
       
    14     _MAX_SCALE: 20,
    27     _AUTOSCALE_MARGIN: 50,
    15     _AUTOSCALE_MARGIN: 50,
    28     _MINIMAP_WIDTH: 160,
       
    29     _MINIMAP_HEIGHT: 120,
       
    30     _USER_PLACEHOLDER : {
    16     _USER_PLACEHOLDER : {
    31         color: "#000000",
    17         color: "#000000",
    32         title: "(unknown user)",
    18         title: "(unknown user)",
    33         get: function(attr) {
    19         get: function(attr) {
    34             return this[attr] || false;
    20             return this[attr] || false;
    43 
    29 
    44 Rkns.Renderer.Utils = {
    30 Rkns.Renderer.Utils = {
    45 	shortenText : function(_text, _maxlength) {
    31 	shortenText : function(_text, _maxlength) {
    46 		return (_text.length > _maxlength ? (_text.substr(0,_maxlength) + '…') : _text);
    32 		return (_text.length > _maxlength ? (_text.substr(0,_maxlength) + '…') : _text);
    47 	},
    33 	},
    48     drawEditBox : function(_coords, _path, _width, _xmargin, _selector) {
    34     drawEditBox : function(_options, _coords, _path, _xmargin, _selector) {
    49         _selector.css({
    35     	_selector.css({
    50             width: (_width - 2* Rkns.Renderer._EDITOR_PADDING),
    36             width: ( _options.tooltip_width - 2* _options.tooltip_margin ),
    51         })
    37         })
    52         var _height = _selector.outerHeight() + 2* Rkns.Renderer._EDITOR_PADDING,
    38         var _height = _selector.outerHeight() + 2* _options.tooltip_padding,
    53             _isLeft = (_coords.x < paper.view.center.x ? 1 : -1),
    39             _isLeft = (_coords.x < paper.view.center.x ? 1 : -1),
    54             _left = _coords.x + _isLeft * ( _xmargin + Rkns.Renderer._EDITOR_ARROW_LENGTH ),
    40             _left = _coords.x + _isLeft * ( _xmargin + _options.tooltip_arrow_length ),
    55             _right = _coords.x + _isLeft * ( _xmargin + Rkns.Renderer._EDITOR_ARROW_LENGTH + _width ),
    41             _right = _coords.x + _isLeft * ( _xmargin + _options.tooltip_arrow_length + _options.tooltip_width ),
    56             _top = _coords.y - _height / 2;
    42             _top = _coords.y - _height / 2;
    57         if (_top < Rkns.Renderer._EDITOR_MARGIN) {
    43         if (_top < _options.tooltip_margin) {
    58             _top = Math.min( Rkns.Renderer._EDITOR_MARGIN, _coords.y - Rkns.Renderer._EDITOR_ARROW_WIDTH / 2 );
    44             _top = Math.min( _options.tooltip_margin, _coords.y - _options.tooltip_arrow_width / 2 );
    59         }
    45         }
    60         var _bottom = _top + _height;
    46         var _bottom = _top + _height;
    61         if (_bottom > (paper.view.size.height - Rkns.Renderer._EDITOR_MARGIN)) {
    47         if (_bottom > (paper.view.size.height - _options.tooltip_margin)) {
    62             _bottom = Math.max( paper.view.size.height - Rkns.Renderer._EDITOR_MARGIN, _coords.y + Rkns.Renderer._EDITOR_ARROW_WIDTH / 2 );
    48             _bottom = Math.max( paper.view.size.height - _options.tooltip_margin, _coords.y + _options.tooltip_arrow_width / 2 );
    63             _top = _bottom - _height;
    49             _top = _bottom - _height;
    64         }
    50         }
    65         _path.segments[0].point
    51         _path.segments[0].point
    66             = _path.segments[7].point
    52             = _path.segments[7].point
    67             = _coords.add([_isLeft * _xmargin, 0]);
    53             = _coords.add([_isLeft * _xmargin, 0]);
    77             = _path.segments[3].point.y
    63             = _path.segments[3].point.y
    78             = _top;
    64             = _top;
    79         _path.segments[4].point.y
    65         _path.segments[4].point.y
    80             = _path.segments[5].point.y
    66             = _path.segments[5].point.y
    81             = _bottom;
    67             = _bottom;
    82         _path.segments[1].point.y = _coords.y - Rkns.Renderer._EDITOR_ARROW_WIDTH / 2;
    68         _path.segments[1].point.y = _coords.y - _options.tooltip_arrow_width / 2;
    83         _path.segments[6].point.y = _coords.y + Rkns.Renderer._EDITOR_ARROW_WIDTH / 2;
    69         _path.segments[6].point.y = _coords.y + _options.tooltip_arrow_width / 2;
    84         _path.closed = true;
    70         _path.closed = true;
    85         _path.fillColor = new paper.GradientColor(Rkns.Renderer._EDITOR_GRADIENT, [0,_top], [0, _bottom]);
    71         _path.fillColor = new paper.GradientColor(new paper.Gradient([_options.tooltip_top_color, _options.tooltip_bottom_color]), [0,_top], [0, _bottom]);
    86         _selector.css({
    72         _selector.css({
    87             left: (Rkns.Renderer._EDITOR_PADDING + Math.min(_left, _right)),
    73             left: (_options.tooltip_padding + Math.min(_left, _right)),
    88             top: (Rkns.Renderer._EDITOR_PADDING + _top)
    74             top: (_options.tooltip_padding + _top)
    89         });
    75         });
    90     },
    76     },
    91     sector : function(_repr, _inR, _outR, _startAngle, _endAngle, _padding, _imgsrc, _caption) {
    77     sector : function(_repr, _inR, _outR, _startAngle, _endAngle, _padding, _imgsrc, _caption) {
    92         var _startRads = _startAngle * Math.PI / 180,
    78         var _options = _repr.renderer.renkan.options,
       
    79         	_startRads = _startAngle * Math.PI / 180,
    93             _endRads = _endAngle * Math.PI / 180,
    80             _endRads = _endAngle * Math.PI / 180,
    94             _img = new Image(),
    81             _img = new Image(),
    95             _span = _endRads - _startRads,
    82             _span = _endRads - _startRads,
    96             _k = .0879 * _span,
    83             _k = .0879 * _span,
    97             _kin = _k * _inR,
    84             _kin = _k * _inR,
   123         var _path = new paper.Path();
   110         var _path = new paper.Path();
   124         _path.add([_startXIn, _startYIn]);
   111         _path.add([_startXIn, _startYIn]);
   125         _path.arcTo([_centerXIn, _centerYIn], [_endXIn, _endYIn]);
   112         _path.arcTo([_centerXIn, _centerYIn], [_endXIn, _endYIn]);
   126         _path.lineTo([_endXOut,  _endYOut]);
   113         _path.lineTo([_endXOut,  _endYOut]);
   127         _path.arcTo([_centerXOut, _centerYOut], [_startXOut, _startYOut]);
   114         _path.arcTo([_centerXOut, _centerYOut], [_startXOut, _startYOut]);
   128         _path.fillColor = "#333333";
   115         _path.fillColor = _options.buttons_background;
   129         _path.opacity = .5;
   116         _path.opacity = .5;
   130         _path.closed = true;
   117         _path.closed = true;
   131         _path.__representation = _repr;
   118         _path.__representation = _repr;
   132         if (_textX >= -2 && _textX <= 2) {
   119         if (_textX >= -2 && _textX <= 2) {
   133             if (_textY > 0) {
   120             if (_textY > 0) {
   134                 _textY += 6;
   121                 _textY += 6;
   135             }
   122             }
   136         }
   123         }
   137         var _text = new paper.PointText(_textX,_textY);
   124         var _text = new paper.PointText(_textX,_textY);
   138         _text.characterStyle = {
   125         _text.characterStyle = {
   139             fontSize: 9,
   126             fontSize: _options.buttons_label_font_size,
   140             fillColor: '#c000c0'
   127             fillColor: _options.buttons_label_color
   141         };
   128         };
   142         if (_textX > 2) {
   129         if (_textX > 2) {
   143             _text.paragraphStyle.justification = 'left';
   130             _text.paragraphStyle.justification = 'left';
   144         } else if (_textX < -2) {
   131         } else if (_textX < -2) {
   145             _text.paragraphStyle.justification = 'right';
   132             _text.paragraphStyle.justification = 'right';
   251 
   238 
   252 Rkns.Renderer.Node.prototype._init = function() {
   239 Rkns.Renderer.Node.prototype._init = function() {
   253     this.renderer.node_layer.activate();
   240     this.renderer.node_layer.activate();
   254     this.type = "Node";
   241     this.type = "Node";
   255     this.circle = new paper.Path.Circle([0, 0], 1);
   242     this.circle = new paper.Path.Circle([0, 0], 1);
       
   243     this.circle.__representation = this;
   256     this.circle.fillColor = '#ffffff';
   244     this.circle.fillColor = '#ffffff';
   257     this.circle.__representation = this;
   245     if (this.renderer.renkan.options.show_node_circles) {
   258     this.circle.strokeWidth = 2;
   246 	    this.circle.strokeWidth = this.renderer.renkan.options.node_stroke_width;
       
   247 	    this.h_ratio = 1;
       
   248     } else {
       
   249     	this.circle.opacity = .01;
       
   250     	this.h_ratio = 0;
       
   251     }
   259     this.title = new paper.PointText([0,0]);
   252     this.title = new paper.PointText([0,0]);
   260     this.title.characterStyle = {
   253     this.title.characterStyle = {
   261         fontSize: Rkns.Renderer._NODE_FONT_SIZE,
   254         font: this.renderer.renkan.options.node_label_font,
   262         fillColor: 'black'
   255         fontSize: this.renderer.renkan.options.node_label_font_size,
       
   256         fillColor: this.renderer.renkan.options.node_label_color
   263     };
   257     };
   264     if (this.renderer.renkan.options.editor_mode) {
   258     if (this.renderer.renkan.options.editor_mode) {
   265         this.edit_button = new Rkns.Renderer.NodeEditButton(this.renderer, null);
   259         this.edit_button = new Rkns.Renderer.NodeEditButton(this.renderer, null);
   266         this.edit_button.node_representation = this;
   260         this.edit_button.node_representation = this;
   267         this.remove_button = new Rkns.Renderer.NodeRemoveButton(this.renderer, null);
   261         this.remove_button = new Rkns.Renderer.NodeRemoveButton(this.renderer, null);
   270         this.link_button.node_representation = this;
   264         this.link_button.node_representation = this;
   271     }
   265     }
   272     this.last_circle_radius = 1;
   266     this.last_circle_radius = 1;
   273     this.title.paragraphStyle.justification = 'center';
   267     this.title.paragraphStyle.justification = 'center';
   274     
   268     
   275     this.renderer.minimap.node_layer.activate();
   269     if (this.renderer.minimap) {
   276     this.minimap_circle = new paper.Path.Circle([0, 0], 1);
   270 	    this.renderer.minimap.node_layer.activate();
   277     this.renderer.minimap.node_group.addChild(this.minimap_circle);
   271 	    this.minimap_circle = new paper.Path.Circle([0, 0], 1);
       
   272 	    this.renderer.minimap.node_group.addChild(this.minimap_circle);
       
   273     }
   278 }
   274 }
   279 
   275 
   280 Rkns.Renderer.Node.prototype.redraw = function(_dontRedrawEdges) {
   276 Rkns.Renderer.Node.prototype.redraw = function(_dontRedrawEdges) {
   281     var _model_coords = new paper.Point(this.model.get("position")),
   277     var _model_coords = new paper.Point(this.model.get("position")),
   282     	_baseRadius = Rkns.Renderer._NODE_SIZE_BASE * Math.exp((this.model.get("size") || 0) * Rkns.Renderer._NODE_SIZE_STEP);
   278     	_baseRadius = Rkns.Renderer._NODE_SIZE_BASE * Math.exp((this.model.get("size") || 0) * Rkns.Renderer._NODE_SIZE_STEP);
   291 	    	this.link_button.setSectorSize();
   287 	    	this.link_button.setSectorSize();
   292 	    }
   288 	    }
   293 	    var square = new paper.Size(this.circle_radius, this.circle_radius),
   289 	    var square = new paper.Size(this.circle_radius, this.circle_radius),
   294 	    	topleft = this.paper_coords.subtract(square),
   290 	    	topleft = this.paper_coords.subtract(square),
   295 	    	bounds = new paper.Rectangle(topleft, square.multiply(2));
   291 	    	bounds = new paper.Rectangle(topleft, square.multiply(2));
   296 	    this.circle.fitBounds(bounds);
   292     	this.circle.fitBounds(bounds);
   297 	    if (this.node_image) {
   293 	    if (this.node_image) {
   298 	    	this.node_image.fitBounds(bounds);
   294 	    	this.node_image.fitBounds(bounds);
   299 	    }
   295 	    }
   300     } else {
   296     } else {
   301     	this.circle.position = this.paper_coords;
   297     	this.circle.position = this.paper_coords;
   304         }
   300         }
   305     }
   301     }
   306     this.last_circle_radius = this.circle_radius;
   302     this.last_circle_radius = this.circle_radius;
   307     
   303     
   308     var _text = this.model.get("title") || this.renderer.renkan.translate("(untitled)");
   304     var _text = this.model.get("title") || this.renderer.renkan.translate("(untitled)");
   309     this.title.content = Rkns.Renderer.Utils.shortenText(_text, Rkns.Renderer._NODE_MAX_CHAR);
   305     this.title.content = Rkns.Renderer.Utils.shortenText(_text, this.renderer.renkan.options.node_label_max_length);
   310 
   306 
   311     this.title.position = this.paper_coords.add([0, this.circle_radius + 1.5 *Rkns.Renderer._NODE_FONT_SIZE]);
   307     this.title.position = this.paper_coords.add([
       
   308     	0,
       
   309     	this.circle_radius * this.h_ratio + this.renderer.renkan.options.node_label_font_size + this.renderer.renkan.options.node_label_distance
       
   310 	]);
   312     var _color = this.model.get("color") || (this.model.get("created_by") || Rkns.Renderer._USER_PLACEHOLDER).get("color");
   311     var _color = this.model.get("color") || (this.model.get("created_by") || Rkns.Renderer._USER_PLACEHOLDER).get("color");
   313     this.circle.strokeColor = _color;
   312     this.circle.strokeColor = _color;
   314     if (this.renderer.renkan.options.editor_mode) {
   313     if (this.renderer.renkan.options.editor_mode) {
   315     	this.edit_button.moveTo(this.paper_coords);
   314     	this.edit_button.moveTo(this.paper_coords);
   316 	    this.remove_button.moveTo(this.paper_coords);
   315 	    this.remove_button.moveTo(this.paper_coords);
   324             if (_this.node_image) {
   323             if (_this.node_image) {
   325                 _this.node_image.remove();
   324                 _this.node_image.remove();
   326             }
   325             }
   327             _this.renderer.node_layer.activate();
   326             _this.renderer.node_layer.activate();
   328             var _ratio = Math.min(2 / _image.width, 2 / _image.height );
   327             var _ratio = Math.min(2 / _image.width, 2 / _image.height );
       
   328             if (!_this.renderer.renkan.options.show_node_circles) {
       
   329             	_this.h_ratio = Math.min(1, _image.height / _image.width);
       
   330             }
   329             var _raster = new paper.Raster(_image);
   331             var _raster = new paper.Raster(_image);
   330             if (_this.renderer.renkan.options.clip_images) {
   332             if (_this.renderer.renkan.options.clip_node_images) {
   331 	            var _clip = new paper.Path.Circle([0, 0], 1);
   333 	            var _clip = new paper.Path.Circle([0, 0], 1);
   332 	            _raster.scale(_ratio);
   334 	            _raster.scale(_ratio);
   333 	            _this.node_image = new paper.Group(_clip, _raster);
   335 	            _this.node_image = new paper.Group(_clip, _raster);
   334 	            _this.node_image.opacity = .9;
   336 	            _this.node_image.opacity = .99;
   335 	            /* This is a workaround to allow clipping at group level
   337 	            /* This is a workaround to allow clipping at group level
   336 	             * If opacity was set to 1, paper.js would merge all clipping groups in one (known bug).
   338 	             * If opacity was set to 1, paper.js would merge all clipping groups in one (known bug).
   337 	            */
   339 	            */
   338 	            _this.node_image.clipped = true;
   340 	            _this.node_image.clipped = true;
       
   341             	_clip.__representation = _this;
   339             } else {
   342             } else {
   340             	_this.node_image = _raster;
   343             	_this.node_image = _raster;
   341             }
   344             }
   342             _this.node_image.__representation = _this;
   345             _this.node_image.__representation = _this;
   343 		    var square = new paper.Size(_this.circle_radius, _this.circle_radius),
   346 		    var square = new paper.Size(_this.circle_radius, _this.circle_radius),
   344 		    	topleft = _this.paper_coords.subtract(square),
   347 		    	topleft = _this.paper_coords.subtract(square),
   345 		    	bounds = new paper.Rectangle(topleft, square.multiply(2));
   348 		    	bounds = new paper.Rectangle(topleft, square.multiply(2));
   346 		    _this.node_image.fitBounds(bounds);
   349 		    _this.node_image.fitBounds(bounds);
   347             _clip.__representation = _this;
   350             _this.redraw();
   348             paper.view.draw();
       
   349         }
   351         }
   350         _image.src = _img;
   352         _image.src = _img;
   351     }
   353     }
   352     this.img = _img;
   354     this.img = _img;
   353     if (this.node_image && !this.img) {
   355     if (this.node_image && !this.img) {
   354         this.node_image.remove();
   356         this.node_image.remove();
   355         delete this.node_image;
   357         delete this.node_image;
   356     }
   358     }
   357     
   359     
   358     this.minimap_circle.fillColor = _color;
   360     if (this.renderer.minimap) {
   359     var minipos = this.renderer.toMinimapCoords(_model_coords),
   361 	    this.minimap_circle.fillColor = _color;
   360     	miniradius = this.renderer.minimap.scale * _baseRadius,
   362 	    var minipos = this.renderer.toMinimapCoords(_model_coords),
   361     	minisize = new paper.Size([miniradius, miniradius]);
   363 	    	miniradius = this.renderer.minimap.scale * _baseRadius,
   362     this.minimap_circle.fitBounds(minipos.subtract(minisize), minisize.multiply(2));
   364 	    	minisize = new paper.Size([miniradius, miniradius]);
       
   365 	    this.minimap_circle.fitBounds(minipos.subtract(minisize), minisize.multiply(2));
       
   366     }
   363     
   367     
   364     if (!_dontRedrawEdges) {
   368     if (!_dontRedrawEdges) {
   365     	Rkns._.each(this.project.get("edges").filter(function (ed) { return ((ed.to === this.model) || (ed.from === this.model));}), function(edge, index, list){
   369     	Rkns._.each(this.project.get("edges").filter(function (ed) { return ((ed.to === this.model) || (ed.from === this.model));}), function(edge, index, list){
   366 	        var repr = this.renderer.getRepresentationByModel(edge);
   370 	        var repr = this.renderer.getRepresentationByModel(edge);
   367 	    	if(repr != null && typeof repr.from_representation.paper_coords !== "undefined" && typeof repr.to_representation.paper_coords !== "undefined") {
   371 	    	if(repr != null && typeof repr.from_representation.paper_coords !== "undefined" && typeof repr.to_representation.paper_coords !== "undefined") {
   390     _editor.node_representation = this;
   394     _editor.node_representation = this;
   391     _editor.draw();
   395     _editor.draw();
   392 }
   396 }
   393 
   397 
   394 Rkns.Renderer.Node.prototype.select = function() {
   398 Rkns.Renderer.Node.prototype.select = function() {
   395     this.circle.strokeWidth = 4;
   399     this.circle.strokeWidth = this.renderer.renkan.options.selected_node_stroke_width;
   396     if (this.renderer.isEditable()) {
   400     if (this.renderer.isEditable()) {
   397 	    this.edit_button.show();
   401 	    this.edit_button.show();
   398 	    this.remove_button.show();
   402 	    this.remove_button.show();
   399 	    this.link_button.show();
   403 	    this.link_button.show();
   400     }
   404     }
   408 	    });
   412 	    });
   409     }
   413     }
   410     if (!this.renderer.renkan.options.editor_mode) {
   414     if (!this.renderer.renkan.options.editor_mode) {
   411         this.openEditor();
   415         this.openEditor();
   412     }
   416     }
   413     this.minimap_circle.fillColor = "#ff00fc";
   417     
       
   418     if (this.renderer.minimap) {
       
   419     	this.minimap_circle.fillColor = "#ff00fc";
       
   420     }
   414 }
   421 }
   415 
   422 
   416 Rkns.Renderer.Node.prototype.unselect = function(_newTarget) {
   423 Rkns.Renderer.Node.prototype.unselect = function(_newTarget) {
   417     if (!_newTarget || _newTarget.node_representation !== this) {
   424     if (!_newTarget || _newTarget.node_representation !== this) {
   418 	    if (this.renderer.renkan.options.editor_mode) {
   425 	    if (this.renderer.renkan.options.editor_mode) {
   419 	        this.edit_button.hide();
   426 	        this.edit_button.hide();
   420 	        this.remove_button.hide();
   427 	        this.remove_button.hide();
   421 	        this.link_button.hide();
   428 	        this.link_button.hide();
   422 	   	}
   429 	   	}
   423         this.circle.strokeWidth = 2;
   430     	this.circle.strokeWidth = this.renderer.renkan.options.node_stroke_width;
   424         Rkns.$('.Rk-Bin-Item').removeClass("selected");
   431         Rkns.$('.Rk-Bin-Item').removeClass("selected");
   425     	this.minimap_circle.fillColor = this.circle.strokeColor;
   432     	if (this.renderer.minimap) {
       
   433     		this.minimap_circle.fillColor = this.model.get("color") || (this.model.get("created_by") || Rkns.Renderer._USER_PLACEHOLDER).get("color");
       
   434     	}
   426     }
   435     }
   427 }
   436 }
   428 
   437 
   429 Rkns.Renderer.Node.prototype.highlight = function() {
   438 Rkns.Renderer.Node.prototype.highlight = function() {
   430     this.circle.fillColor = "#ffff80";
   439     this.circle.fillColor = "#ffff80";
   434 }
   443 }
   435 
   444 
   436 Rkns.Renderer.Node.prototype.unhighlight = function(_newTarget) {
   445 Rkns.Renderer.Node.prototype.unhighlight = function(_newTarget) {
   437     this.circle.fillColor = "#ffffff";
   446     this.circle.fillColor = "#ffffff";
   438     if (this.node_image) {
   447     if (this.node_image) {
   439         this.node_image.opacity = .9;
   448         this.node_image.opacity = .99;
   440     }
   449     }
   441 }
   450 }
   442 
   451 
   443 Rkns.Renderer.Node.prototype.saveCoords = function() {
   452 Rkns.Renderer.Node.prototype.saveCoords = function() {
   444     var _coords = this.renderer.toModelCoords(this.paper_coords),
   453     var _coords = this.renderer.toModelCoords(this.paper_coords),
   472 	    this.remove_button.destroy();
   481 	    this.remove_button.destroy();
   473 	    this.link_button.destroy();
   482 	    this.link_button.destroy();
   474     }
   483     }
   475     this.circle.remove();
   484     this.circle.remove();
   476     this.title.remove();
   485     this.title.remove();
   477     this.minimap_circle.remove();
   486     if (this.renderer.minimap) {
       
   487     	this.minimap_circle.remove();
       
   488     }
   478     if (this.node_image) {
   489     if (this.node_image) {
   479         this.node_image.remove();
   490         this.node_image.remove();
   480     }
   491     }
   481 }
   492 }
   482 
   493 
   491     this.to_representation = this.renderer.getRepresentationByModel(this.model.get("to"));
   502     this.to_representation = this.renderer.getRepresentationByModel(this.model.get("to"));
   492     this.bundle = this.renderer.addToBundles(this);
   503     this.bundle = this.renderer.addToBundles(this);
   493     this.line = new paper.Path();
   504     this.line = new paper.Path();
   494     this.line.add([0,0],[0,0],[0,0]);
   505     this.line.add([0,0],[0,0],[0,0]);
   495     this.line.__representation = this;
   506     this.line.__representation = this;
   496     this.line.strokeWidth = 2;
   507     this.line.strokeWidth = this.renderer.renkan.options.edge_stroke_width;
   497     this.arrow = new paper.Path();
   508     this.arrow = new paper.Path();
   498     this.arrow.add([0,0],[Rkns.Renderer._ARROW_LENGTH,Rkns.Renderer._ARROW_WIDTH / 2],[0,Rkns.Renderer._ARROW_WIDTH]);
   509     this.arrow.add(
       
   510     	[ 0, 0 ],
       
   511     	[ this.renderer.renkan.options.edge_arrow_length, this.renderer.renkan.options.edge_arrow_width / 2 ],
       
   512     	[ 0, this.renderer.renkan.options.edge_arrow_width ]
       
   513 	);
   499     this.arrow.__representation = this;
   514     this.arrow.__representation = this;
   500     this.text = new paper.PointText();
   515     this.text = new paper.PointText();
   501     this.text.characterStyle = {
   516     this.text.characterStyle = {
   502         fontSize: Rkns.Renderer._EDGE_FONT_SIZE,
   517         font: this.renderer.renkan.options.edge_label_font,
   503         fillColor: 'black'
   518         fontSize: this.renderer.renkan.options.edge_label_font_size,
       
   519         fillColor: this.renderer.renkan.options.edge_label_color
   504     };
   520     };
   505     this.text.paragraphStyle.justification = 'center';
   521     this.text.paragraphStyle.justification = 'center';
   506     this.text_angle = 0;
   522     this.text_angle = 0;
   507     this.arrow_angle = 0;
   523     this.arrow_angle = 0;
   508     if (this.renderer.renkan.options.editor_mode) {
   524     if (this.renderer.renkan.options.editor_mode) {
   509         this.edit_button = new Rkns.Renderer.EdgeEditButton(this.renderer, null);
   525         this.edit_button = new Rkns.Renderer.EdgeEditButton(this.renderer, null);
   510         this.edit_button.edge_representation = this;
   526         this.edit_button.edge_representation = this;
   511         this.remove_button = new Rkns.Renderer.EdgeRemoveButton(this.renderer, null);
   527         this.remove_button = new Rkns.Renderer.EdgeRemoveButton(this.renderer, null);
   512         this.remove_button.edge_representation = this;
   528         this.remove_button.edge_representation = this;
   513     }
   529     }
       
   530     
       
   531     if (this.renderer.minimap) {
       
   532     	this.renderer.minimap.edge_layer.activate();
       
   533 	    this.minimap_line = new paper.Path();
       
   534 	    this.minimap_line.add([0,0],[0,0]);
       
   535 	    this.minimap_line.strokeWidth = 1;
       
   536     }
   514 }
   537 }
   515 
   538 
   516 Rkns.Renderer.Edge.prototype.redraw = function() {
   539 Rkns.Renderer.Edge.prototype.redraw = function() {
   517     this.from_representation = this.renderer.getRepresentationByModel(this.model.get("from"));
   540     this.from_representation = this.renderer.getRepresentationByModel(this.model.get("from"));
   518     this.to_representation = this.renderer.getRepresentationByModel(this.model.get("to"));
   541     this.to_representation = this.renderer.getRepresentationByModel(this.model.get("to"));
   524         _v = _p1a.subtract(_p0a),
   547         _v = _p1a.subtract(_p0a),
   525         _r = _v.length,
   548         _r = _v.length,
   526         _u = _v.divide(_r),
   549         _u = _v.divide(_r),
   527         _ortho = new paper.Point([- _u.y, _u.x]),
   550         _ortho = new paper.Point([- _u.y, _u.x]),
   528         _group_pos = this.bundle.getPosition(this),
   551         _group_pos = this.bundle.getPosition(this),
   529         _delta = _ortho.multiply( 12 * _group_pos ),
   552         _delta = _ortho.multiply( this.renderer.renkan.options.edge_gap_in_bundles * _group_pos ),
   530         _p0b = _p0a.add(_delta), /* Adding a 4 px difference */
   553         _p0b = _p0a.add(_delta), /* Adding a 4 px difference */
   531         _p1b = _p1a.add(_delta), /* to differentiate inbound and outbound links */
   554         _p1b = _p1a.add(_delta), /* to differentiate bundled links */
   532         _a = _v.angle,
   555         _a = _v.angle,
   533         _textdelta = _ortho.multiply(-Rkns.Renderer._EDGE_DISTANCE),
   556         _textdelta = _ortho.multiply(this.renderer.renkan.options.edge_label_distance),
   534         _handle = _v.divide(3),
   557         _handle = _v.divide(3),
   535         _color = this.model.get("color") || this.model.get("color") || (this.model.get("created_by") || Rkns.Renderer._USER_PLACEHOLDER).get("color");
   558         _color = this.model.get("color") || this.model.get("color") || (this.model.get("created_by") || Rkns.Renderer._USER_PLACEHOLDER).get("color");
   536     this.paper_coords = _p0b.add(_p1b).divide(2);
   559     this.paper_coords = _p0b.add(_p1b).divide(2);
   537     this.line.strokeColor = _color;
   560     this.line.strokeColor = _color;
   538     this.line.segments[0].point = _p0a;
   561     this.line.segments[0].point = _p0a;
   540     this.line.segments[1].handleIn = _handle.multiply(-1);
   563     this.line.segments[1].handleIn = _handle.multiply(-1);
   541     this.line.segments[1].handleOut = _handle;
   564     this.line.segments[1].handleOut = _handle;
   542     this.line.segments[2].point = _p1a;
   565     this.line.segments[2].point = _p1a;
   543     this.arrow.rotate(_a - this.arrow_angle);
   566     this.arrow.rotate(_a - this.arrow_angle);
   544     this.arrow.fillColor = _color;
   567     this.arrow.fillColor = _color;
   545     this.arrow.position = this.paper_coords.subtract(_u.multiply(4));
   568     this.arrow.position = this.paper_coords;
   546     this.arrow_angle = _a;
   569     this.arrow_angle = _a;
   547     if (_a > 90) {
   570     if (_a > 90) {
   548         _a -= 180;
   571         _a -= 180;
   549         _textdelta = _textdelta.multiply(-1);
   572         _textdelta = _textdelta.multiply(-1);
   550     }
   573     }
   552         _a += 180;
   575         _a += 180;
   553         _textdelta = _textdelta.multiply(-1);
   576         _textdelta = _textdelta.multiply(-1);
   554     }
   577     }
   555     this.text.rotate(_a - this.text_angle);
   578     this.text.rotate(_a - this.text_angle);
   556     var _text = this.model.get("title");
   579     var _text = this.model.get("title");
   557     this.text.content = Rkns.Renderer.Utils.shortenText(_text, Rkns.Renderer._EDGE_MAX_CHAR);
   580     this.text.content = Rkns.Renderer.Utils.shortenText(_text, this.renderer.renkan.options.edge_label_max_length);
   558     this.text.position = this.paper_coords.add(_textdelta);
   581     this.text.position = this.paper_coords.add(_textdelta);
   559     this.text_angle = _a;
   582     this.text_angle = _a;
   560     if (this.renderer.renkan.options.editor_mode) {
   583     if (this.renderer.renkan.options.editor_mode) {
   561 	    this.edit_button.moveTo(this.paper_coords);
   584 	    this.edit_button.moveTo(this.paper_coords);
   562 	    this.remove_button.moveTo(this.paper_coords);
   585 	    this.remove_button.moveTo(this.paper_coords);
   563     }
   586     }
       
   587     
       
   588     if (this.renderer.minimap) {
       
   589 	    this.minimap_line.strokeColor = _color;
       
   590 	    this.minimap_line.segments[0].point = this.renderer.toMinimapCoords(new paper.Point(this.from_representation.model.get("position")));
       
   591  	    this.minimap_line.segments[1].point = this.renderer.toMinimapCoords(new paper.Point(this.to_representation.model.get("position")));
       
   592     }
   564 }
   593 }
   565 
   594 
   566 Rkns.Renderer.Edge.prototype.openEditor = function() {
   595 Rkns.Renderer.Edge.prototype.openEditor = function() {
   567     this.renderer.removeRepresentationsOfType("editor");
   596     this.renderer.removeRepresentationsOfType("editor");
   568     var _editor = this.renderer.addRepresentation("EdgeEditor",null);
   597     var _editor = this.renderer.addRepresentation("EdgeEditor",null);
   569     _editor.edge_representation = this;
   598     _editor.edge_representation = this;
   570     _editor.draw();
   599     _editor.draw();
   571 }
   600 }
   572 
   601 
   573 Rkns.Renderer.Edge.prototype.select = function() {
   602 Rkns.Renderer.Edge.prototype.select = function() {
   574     this.line.strokeWidth = 4;
   603     this.line.strokeWidth = this.renderer.renkan.options.selected_edge_stroke_width;
   575     if (this.renderer.isEditable()) {
   604     if (this.renderer.isEditable()) {
   576 	    this.edit_button.show();
   605 	    this.edit_button.show();
   577 	    this.remove_button.show();
   606 	    this.remove_button.show();
   578    	}
   607    	}
   579     if (!this.renderer.renkan.options.editor_mode) {
   608     if (!this.renderer.renkan.options.editor_mode) {
   585     if (!_newTarget || _newTarget.edge_representation !== this) {
   614     if (!_newTarget || _newTarget.edge_representation !== this) {
   586     	if (this.renderer.renkan.options.editor_mode) {
   615     	if (this.renderer.renkan.options.editor_mode) {
   587 	        this.edit_button.hide();
   616 	        this.edit_button.hide();
   588 	        this.remove_button.hide();
   617 	        this.remove_button.hide();
   589         }
   618         }
   590         this.line.strokeWidth = 2;
   619         this.line.strokeWidth = this.renderer.renkan.options.edge_stroke_width;
   591     }
   620     }
   592 }
   621 }
   593 
   622 
   594 Rkns.Renderer.Edge.prototype.mouseup = function(_event) {
   623 Rkns.Renderer.Edge.prototype.mouseup = function(_event) {
   595     if (!this.renderer.renkan.read_only) {
   624     if (!this.renderer.renkan.read_only) {
   618 Rkns.Renderer.Edge.prototype.destroy = function() {
   647 Rkns.Renderer.Edge.prototype.destroy = function() {
   619     this.super("destroy");
   648     this.super("destroy");
   620     this.line.remove();
   649     this.line.remove();
   621     this.arrow.remove();
   650     this.arrow.remove();
   622     this.text.remove();
   651     this.text.remove();
       
   652     if (this.renderer.minimap) {
       
   653    	    this.minimap_line.remove();
       
   654     }
   623     if (this.renderer.renkan.options.editor_mode) {
   655     if (this.renderer.renkan.options.editor_mode) {
   624 	    this.edit_button.destroy();
   656 	    this.edit_button.destroy();
   625 	    this.remove_button.destroy();
   657 	    this.remove_button.destroy();
   626    	}
   658    	}
   627     var _this = this;
   659     var _this = this;
   643     this.line.strokeColor = _color;
   675     this.line.strokeColor = _color;
   644     this.line.add([0,0],[0,0]);
   676     this.line.add([0,0],[0,0]);
   645     this.line.__representation = this;
   677     this.line.__representation = this;
   646     this.arrow = new paper.Path();
   678     this.arrow = new paper.Path();
   647     this.arrow.fillColor = _color;
   679     this.arrow.fillColor = _color;
   648     this.arrow.add([0,0],[Rkns.Renderer._ARROW_LENGTH,Rkns.Renderer._ARROW_WIDTH / 2],[0,Rkns.Renderer._ARROW_WIDTH]);
   680     this.arrow.add(
       
   681     	[ 0, 0 ],
       
   682     	[ this.renderer.renkan.options.edge_arrow_length, this.renderer.renkan.options.edge_arrow_width / 2 ],
       
   683     	[ 0, this.renderer.renkan.options.edge_arrow_width ]
       
   684 	);
   649     this.arrow.__representation = this;
   685     this.arrow.__representation = this;
   650     this.arrow_angle = 0;
   686     this.arrow_angle = 0;
   651 }
   687 }
   652 
   688 
   653 Rkns.Renderer.TempEdge.prototype.redraw = function() {
   689 Rkns.Renderer.TempEdge.prototype.redraw = function() {
   872     });
   908     });
   873 }
   909 }
   874 
   910 
   875 Rkns.Renderer.NodeEditor.prototype.redraw = function() {
   911 Rkns.Renderer.NodeEditor.prototype.redraw = function() {
   876     var _coords = this.node_representation.paper_coords;
   912     var _coords = this.node_representation.paper_coords;
   877     Rkns.Renderer.Utils.drawEditBox(_coords, this.editor_block, Rkns.Renderer._EDITOR_WIDTH, 20, this.editor_$);
   913     Rkns.Renderer.Utils.drawEditBox(this.renderer.renkan.options, _coords, this.editor_block, this.node_representation.circle_radius * .75, this.editor_$);
   878     this.editor_$.show();
   914     this.editor_$.show();
   879     paper.view.draw();
   915     paper.view.draw();
   880 }
   916 }
   881 
   917 
   882 Rkns.Renderer.NodeEditor.prototype.destroy = function() {
   918 Rkns.Renderer.NodeEditor.prototype.destroy = function() {
  1023     }
  1059     }
  1024 }
  1060 }
  1025 
  1061 
  1026 Rkns.Renderer.EdgeEditor.prototype.redraw = function() {
  1062 Rkns.Renderer.EdgeEditor.prototype.redraw = function() {
  1027     var _coords = this.edge_representation.paper_coords;
  1063     var _coords = this.edge_representation.paper_coords;
  1028     Rkns.Renderer.Utils.drawEditBox(_coords, this.editor_block, Rkns.Renderer._EDITOR_WIDTH, 5, this.editor_$);
  1064     Rkns.Renderer.Utils.drawEditBox(this.renderer.renkan.options, _coords, this.editor_block, 5, this.editor_$);
  1029     this.editor_$.show();
  1065     this.editor_$.show();
  1030     paper.view.draw();
  1066     paper.view.draw();
  1031 }
  1067 }
  1032 
  1068 
  1033 Rkns.Renderer.EdgeEditor.prototype.destroy = function() {
  1069 Rkns.Renderer.EdgeEditor.prototype.destroy = function() {
  1306     this.selected_target = null;
  1342     this.selected_target = null;
  1307     this.edge_layer = new paper.Layer();
  1343     this.edge_layer = new paper.Layer();
  1308     this.node_layer = new paper.Layer();
  1344     this.node_layer = new paper.Layer();
  1309     this.buttons_layer = new paper.Layer();
  1345     this.buttons_layer = new paper.Layer();
  1310     
  1346     
  1311     this.minimap = {
  1347     if (_renkan.options.show_minimap) {
  1312     	background_layer: new paper.Layer(),
  1348 	    this.minimap = {
  1313     	node_layer: new paper.Layer(),
  1349 	    	background_layer: new paper.Layer(),
  1314     	node_group: new paper.Group(),
  1350 	    	edge_layer: new paper.Layer(),
  1315     	size: new paper.Size( Rkns.Renderer._MINIMAP_WIDTH, Rkns.Renderer._MINIMAP_HEIGHT )
  1351 	    	node_layer: new paper.Layer(),
  1316     }
  1352 	    	node_group: new paper.Group(),
  1317     
  1353 	    	size: new paper.Size( _renkan.options.minimap_width, _renkan.options.minimap_height )
  1318     this.minimap.background_layer.activate();
  1354 	    }
  1319     this.minimap.topleft = paper.view.bounds.bottomRight.subtract(this.minimap.size);
  1355 	    
  1320     this.minimap.rectangle = new paper.Path.Rectangle(this.minimap.topleft.subtract([2,2]), this.minimap.size.add([4,4]));
  1356 	    this.minimap.background_layer.activate();
  1321     this.minimap.rectangle.fillColor = '#ffffff';
  1357 	    this.minimap.topleft = paper.view.bounds.bottomRight.subtract(this.minimap.size);
  1322     this.minimap.rectangle.strokeColor = '#cccccc';
  1358 	    this.minimap.rectangle = new paper.Path.Rectangle(this.minimap.topleft.subtract([2,2]), this.minimap.size.add([4,4]));
  1323     this.minimap.rectangle.strokeWidth = 4;
  1359 	    this.minimap.rectangle.fillColor = '#ffffff';
  1324     this.minimap.offset = new paper.Point(this.minimap.size.divide(2));
  1360 	    this.minimap.rectangle.strokeColor = '#cccccc';
  1325     this.minimap.scale = .1;
  1361 	    this.minimap.rectangle.strokeWidth = 4;
  1326     
  1362 	    this.minimap.offset = new paper.Point(this.minimap.size.divide(2));
  1327     this.node_layer.activate();
  1363 	    this.minimap.scale = .1;
  1328     this.minimap.cliprectangle = new paper.Path.Rectangle(this.minimap.topleft, this.minimap.size);
  1364 	    
  1329     this.minimap.node_group.addChild(this.minimap.cliprectangle);
  1365 	    this.minimap.node_layer.activate();
  1330     this.minimap.node_group.clipped = true;
  1366 	    this.minimap.cliprectangle = new paper.Path.Rectangle(this.minimap.topleft, this.minimap.size);
  1331     this.minimap.miniframe = new paper.Path.Rectangle(this.minimap.topleft, this.minimap.size);
  1367 	    this.minimap.node_group.addChild(this.minimap.cliprectangle);
  1332     this.minimap.node_group.addChild(this.minimap.miniframe);
  1368 	    this.minimap.node_group.clipped = true;
  1333     this.minimap.miniframe.fillColor = '#f0f0ff';
  1369 	    this.minimap.miniframe = new paper.Path.Rectangle(this.minimap.topleft, this.minimap.size);
  1334     this.minimap.miniframe.strokeColor = '#8080ff';
  1370 	    this.minimap.node_group.addChild(this.minimap.miniframe);
  1335     this.minimap.miniframe.strokeWidth = 2;
  1371 	    this.minimap.miniframe.fillColor = '#c0c0ff';
  1336     this.minimap.miniframe.__representation = new Rkns.Renderer.MiniFrame(this, null);
  1372 	    this.minimap.miniframe.opacity = .3;
       
  1373 	    this.minimap.miniframe.strokeColor = '#000080';
       
  1374 	    this.minimap.miniframe.strokeWidth = 3;
       
  1375 	    this.minimap.miniframe.__representation = new Rkns.Renderer.MiniFrame(this, null);
       
  1376     }
  1337     
  1377     
  1338     this.bundles = [];
  1378     this.bundles = [];
  1339     this.click_mode = false;
  1379     this.click_mode = false;
  1340     var _tool = new paper.Tool(),
  1380     var _tool = new paper.Tool(),
  1341         _this = this,
  1381         _this = this,
  1483         	var _node = _this.renkan.project.addNode(_data);
  1523         	var _node = _this.renkan.project.addNode(_data);
  1484             _this.getRepresentationByModel(_node).openEditor();
  1524             _this.getRepresentationByModel(_node).openEditor();
  1485     	}
  1525     	}
  1486     })
  1526     })
  1487     this.editor_$.find(".Rk-ZoomOut").click(function() {
  1527     this.editor_$.find(".Rk-ZoomOut").click(function() {
  1488         _this.offset = new paper.Point([
  1528     	var _newScale = _this.scale * Math.SQRT1_2,
  1489             _this.canvas_$.width(),
  1529     		_offset = new paper.Point([
  1490             _this.canvas_$.height()
  1530 	            _this.canvas_$.width(),
  1491         ]).multiply( .5 * ( 1 - Math.SQRT1_2 ) ).add(_this.offset.multiply( Math.SQRT1_2 ));
  1531 	            _this.canvas_$.height()
  1492         _this.setScale( _this.scale * Math.SQRT1_2 );
  1532 	        ]).multiply( .5 * ( 1 - Math.SQRT1_2 ) ).add(_this.offset.multiply( Math.SQRT1_2 ));
  1493         _this.redraw();
  1533         _this.setScale( _newScale, _offset );
  1494     });
  1534     });
  1495     this.editor_$.find(".Rk-ZoomIn").click(function() {
  1535     this.editor_$.find(".Rk-ZoomIn").click(function() {
  1496         _this.offset = new paper.Point([
  1536     	var _newScale = _this.scale * Math.SQRT2,
  1497             _this.canvas_$.width(),
  1537     		_offset = new paper.Point([
  1498             _this.canvas_$.height()
  1538 	            _this.canvas_$.width(),
  1499         ]).multiply( .5 * ( 1 - Math.SQRT2 ) ).add(_this.offset.multiply( Math.SQRT2 ));
  1539 	            _this.canvas_$.height()
  1500         _this.setScale( _this.scale * Math.SQRT2 );
  1540 	        ]).multiply( .5 * ( 1 - Math.SQRT2 ) ).add(_this.offset.multiply( Math.SQRT2 ));
  1501         _this.redraw();
  1541         _this.setScale( _newScale, _offset );
  1502     });
  1542     });
  1503     this.$.find(".Rk-CurrentUser").mouseenter(
  1543     this.$.find(".Rk-CurrentUser").mouseenter(
  1504         function() { _this.$.find(".Rk-UserList").slideDown() }
  1544         function() { _this.$.find(".Rk-UserList").slideDown() }
  1505     );
  1545     );
  1506     this.$.find(".Rk-Users").mouseleave(
  1546     this.$.find(".Rk-Users").mouseleave(
  1579     	}
  1619     	}
  1580     });
  1620     });
  1581     
  1621     
  1582     paper.view.onResize = function(_event) {
  1622     paper.view.onResize = function(_event) {
  1583     	_this.offset = _this.offset.add(_event.delta.divide(2));
  1623     	_this.offset = _this.offset.add(_event.delta.divide(2));
  1584         _this.minimap.topleft = paper.view.bounds.bottomRight.subtract(_this.minimap.size)
  1624     	if (_this.minimap) {
  1585         _this.minimap.rectangle.fitBounds(_this.minimap.topleft.subtract([2,2]), _this.minimap.size.add([4,4]));
  1625 	        _this.minimap.topleft = paper.view.bounds.bottomRight.subtract(_this.minimap.size)
  1586         _this.minimap.cliprectangle.fitBounds(_this.minimap.topleft, _this.minimap.size);
  1626 	        _this.minimap.rectangle.fitBounds(_this.minimap.topleft.subtract([2,2]), _this.minimap.size.add([4,4]));
       
  1627 	        _this.minimap.cliprectangle.fitBounds(_this.minimap.topleft, _this.minimap.size);
       
  1628         }
  1587         _this.redraw();
  1629         _this.redraw();
  1588     }
  1630     }
  1589     
  1631     
  1590     var _thRedraw = Rkns._.throttle(function() {
  1632     var _thRedraw = Rkns._.throttle(function() {
  1591         _this.redraw();
  1633         _this.redraw();
  1626             el.text(_title);
  1668             el.text(_title);
  1627         }
  1669         }
  1628     });
  1670     });
  1629     
  1671     
  1630     this.redraw();
  1672     this.redraw();
  1631     window.setInterval(function() {
  1673     
  1632     	_this.rescaleMinimap()
  1674     if (this.minimap) {
  1633     }, 2000);
  1675 	    window.setInterval(function() {
       
  1676 	    	_this.rescaleMinimap()
       
  1677 	    }, 2000);
       
  1678     }
  1634 }
  1679 }
  1635 
  1680 
  1636 Rkns.Renderer.Scene.prototype.template = Rkns._.template(
  1681 Rkns.Renderer.Scene.prototype.template = Rkns._.template(
  1637     '<div class="Rk-TopBar"><% if (!options.editor_mode) { %><h2 class="Rk-PadTitle"><%- project.get("title") || translate("Untitled project")%></h2>'
  1682     '<div class="Rk-TopBar"><% if (!options.editor_mode) { %><h2 class="Rk-PadTitle"><%- project.get("title") || translate("Untitled project")%></h2>'
  1638     + '<% } else { %><input type="text" class="Rk-PadTitle" value="<%- project.get("title") || "" %>" placeholder="<%-translate("Untitled project")%>" /><% } %>'
  1683     + '<% } else { %><input type="text" class="Rk-PadTitle" value="<%- project.get("title") || "" %>" placeholder="<%-translate("Untitled project")%>" /><% } %>'
  1695 			tip.text(this.renkan.translate("Auto-save enabled"));
  1740 			tip.text(this.renkan.translate("Auto-save enabled"));
  1696 		}
  1741 		}
  1697 	}
  1742 	}
  1698 }
  1743 }
  1699 
  1744 
  1700 Rkns.Renderer.Scene.prototype.setScale = function(_newScale) {
  1745 Rkns.Renderer.Scene.prototype.setScale = function(_newScale, _offset) {
  1701     this.scale = _newScale;
  1746 	if (_newScale > Rkns.Renderer._MIN_SCALE && _newScale < Rkns.Renderer._MAX_SCALE) {
  1702     this.redraw();
  1747 	    this.scale = _newScale;
       
  1748 	    if (_offset) {
       
  1749 	    	this.offset = _offset
       
  1750 	    }
       
  1751 	    this.redraw();
       
  1752     }
  1703 }
  1753 }
  1704 
  1754 
  1705 Rkns.Renderer.Scene.prototype.autoScale = function() {
  1755 Rkns.Renderer.Scene.prototype.autoScale = function() {
  1706     var nodes = this.renkan.project.get("nodes")
  1756     var nodes = this.renkan.project.get("nodes")
  1707     if (nodes.length > 1) {
  1757     if (nodes.length > 1) {
  1709             _yy = nodes.map(function(_node) { return _node.get("position").y }),
  1759             _yy = nodes.map(function(_node) { return _node.get("position").y }),
  1710             _minx = Math.min.apply(Math, _xx),
  1760             _minx = Math.min.apply(Math, _xx),
  1711             _miny = Math.min.apply(Math, _yy),
  1761             _miny = Math.min.apply(Math, _yy),
  1712             _maxx = Math.max.apply(Math, _xx),
  1762             _maxx = Math.max.apply(Math, _xx),
  1713             _maxy = Math.max.apply(Math, _yy);
  1763             _maxy = Math.max.apply(Math, _yy);
  1714         var _scale = Math.min((paper.view.size.width - 2 * Rkns.Renderer._AUTOSCALE_MARGIN) / (_maxx - _minx), (paper.view.size.height - 2 * Rkns.Renderer._AUTOSCALE_MARGIN) / (_maxy - _miny));
  1764         var _scale = Math.max(Rkns.Renderer._MIN_SCALE, Math.min(Rkns.Renderer._MAX_SCALE, (paper.view.size.width - 2 * Rkns.Renderer._AUTOSCALE_MARGIN) / (_maxx - _minx), (paper.view.size.height - 2 * Rkns.Renderer._AUTOSCALE_MARGIN) / (_maxy - _miny)));
  1715 		this.offset = paper.view.center.subtract(new paper.Point([(_maxx + _minx) / 2, (_maxy + _miny) / 2]).multiply(_scale));
  1765 		this.setScale(_scale, paper.view.center.subtract(new paper.Point([(_maxx + _minx) / 2, (_maxy + _miny) / 2]).multiply(_scale)));
  1716         this.setScale(_scale);
       
  1717     }
  1766     }
  1718     if (nodes.length === 1) {
  1767     if (nodes.length === 1) {
  1719         this.offset = paper.view.center.subtract(new paper.Point([nodes.at(0).get("position").x, nodes.at(0).get("position").y]));
  1768         this.setScale(1, paper.view.center.subtract(new paper.Point([nodes.at(0).get("position").x, nodes.at(0).get("position").y])));
  1720         this.setScale(1);
       
  1721     }
  1769     }
  1722 }
  1770 }
  1723 
  1771 
  1724 Rkns.Renderer.Scene.prototype.redrawMiniframe = function() {
  1772 Rkns.Renderer.Scene.prototype.redrawMiniframe = function() {
  1725 	var topleft = this.toMinimapCoords(this.toModelCoords(new paper.Point([0,0]))),
  1773 	var topleft = this.toMinimapCoords(this.toModelCoords(new paper.Point([0,0]))),
  1734             _yy = nodes.map(function(_node) { return _node.get("position").y }),
  1782             _yy = nodes.map(function(_node) { return _node.get("position").y }),
  1735             _minx = Math.min.apply(Math, _xx),
  1783             _minx = Math.min.apply(Math, _xx),
  1736             _miny = Math.min.apply(Math, _yy),
  1784             _miny = Math.min.apply(Math, _yy),
  1737             _maxx = Math.max.apply(Math, _xx),
  1785             _maxx = Math.max.apply(Math, _xx),
  1738             _maxy = Math.max.apply(Math, _yy);
  1786             _maxy = Math.max.apply(Math, _yy);
  1739         var _scale = Math.min(this.scale * .8 * Rkns.Renderer._MINIMAP_WIDTH / paper.view.bounds.width, this.scale * .8 * Rkns.Renderer._MINIMAP_HEIGHT / paper.view.bounds.height, (Rkns.Renderer._MINIMAP_WIDTH - 2 * Rkns.Renderer._MINIMAP_MARGIN_X) / (_maxx - _minx), (Rkns.Renderer._MINIMAP_HEIGHT - 2 * Rkns.Renderer._MINIMAP_MARGIN_Y) / (_maxy - _miny));
  1787         var _scale = Math.min(
       
  1788         	this.scale * .8 * this.renkan.options.minimap_width / paper.view.bounds.width,
       
  1789         	this.scale * .8 * this.renkan.options.minimap_height / paper.view.bounds.height,
       
  1790         	( this.renkan.options.minimap_width - 2 * Rkns.Renderer._MINIMAP_MARGIN ) / (_maxx - _minx),
       
  1791         	( this.renkan.options.minimap_height - 2 * Rkns.Renderer._MINIMAP_MARGIN ) / (_maxy - _miny)
       
  1792     	);
  1740         this.minimap.offset = this.minimap.size.divide(2).subtract(new paper.Point([(_maxx + _minx) / 2, (_maxy + _miny) / 2]).multiply(_scale));
  1793         this.minimap.offset = this.minimap.size.divide(2).subtract(new paper.Point([(_maxx + _minx) / 2, (_maxy + _miny) / 2]).multiply(_scale));
  1741         this.minimap.scale = _scale;
  1794         this.minimap.scale = _scale;
  1742     }
  1795     }
  1743     if (nodes.length === 1) {
  1796     if (nodes.length === 1) {
  1744     	this.minimap.scale = .1;
  1797     	this.minimap.scale = .1;
  1832 
  1885 
  1833 Rkns.Renderer.Scene.prototype.redraw = function() {
  1886 Rkns.Renderer.Scene.prototype.redraw = function() {
  1834     Rkns._(this.representations).each(function(_representation) {
  1887     Rkns._(this.representations).each(function(_representation) {
  1835     	_representation.redraw(true);
  1888     	_representation.redraw(true);
  1836     });
  1889     });
  1837     this.redrawMiniframe();
  1890     if (this.minimap) {
       
  1891     	this.redrawMiniframe();
       
  1892     }
  1838     paper.view.draw();
  1893     paper.view.draw();
  1839 }
  1894 }
  1840 
  1895 
  1841 Rkns.Renderer.Scene.prototype.addTempEdge = function(_from, _point) {
  1896 Rkns.Renderer.Scene.prototype.addTempEdge = function(_from, _point) {
  1842     var _tmpEdge = this.addRepresentation("TempEdge",null);
  1897     var _tmpEdge = this.addRepresentation("TempEdge",null);
  1954             _delta = new paper.Point([
  2009             _delta = new paper.Point([
  1955                 _event.pageX - _off.left,
  2010                 _event.pageX - _off.left,
  1956                 _event.pageY - _off.top
  2011                 _event.pageY - _off.top
  1957             ]).subtract(this.offset).multiply( Math.SQRT2 - 1 );
  2012             ]).subtract(this.offset).multiply( Math.SQRT2 - 1 );
  1958         if (this.totalScroll > 0) {
  2013         if (this.totalScroll > 0) {
  1959             this.offset = this.offset.subtract(_delta);
  2014         	this.setScale( this.scale * Math.SQRT2, this.offset.subtract(_delta) );
  1960             this.setScale( this.scale * Math.SQRT2 );
       
  1961         } else {
  2015         } else {
  1962             this.offset = this.offset.add(_delta.divide( Math.SQRT2 ));
  2016         	this.setScale( this.scale * Math.SQRT1_2, this.offset.add(_delta.divide(Math.SQRT2)));
  1963             this.setScale( this.scale * Math.SQRT1_2);
       
  1964         }
  2017         }
  1965         this.totalScroll = 0;
  2018         this.totalScroll = 0;
  1966         this.redraw();
       
  1967     }
  2019     }
  1968 }
  2020 }
  1969 
  2021 
  1970 Rkns.Renderer.Scene.prototype.onDoubleClick = function(_event) {
  2022 Rkns.Renderer.Scene.prototype.onDoubleClick = function(_event) {
  1971     if (!this.isEditable()) {
  2023     if (!this.isEditable()) {