client/js/paper-renderer.js
changeset 284 fa8035885814
parent 283 67f3a24a7c01
equal deleted inserted replaced
283:67f3a24a7c01 284:fa8035885814
     9 
     9 
    10     /* Rkns.Renderer Object */
    10     /* Rkns.Renderer Object */
    11 
    11 
    12     /* This object contains constants, utility functions and classes for Renkan's Graph Manipulation GUI */
    12     /* This object contains constants, utility functions and classes for Renkan's Graph Manipulation GUI */
    13 
    13 
    14     var Renderer = Rkns.Renderer = {},
    14     var Renderer = Rkns.Renderer = {};
    15     /* The minimum distance (in pixels) the mouse has to move to consider an element was dragged */
       
    16     _MIN_DRAG_DISTANCE = 2,
       
    17     /* Distance between the inner and outer radius of buttons that appear when hovering on a node */
       
    18     _NODE_BUTTON_WIDTH = 40,
       
    19 
       
    20     _EDGE_BUTTON_INNER = 2,
       
    21     _EDGE_BUTTON_OUTER = 40,
       
    22     /* Constants used to know if a specific action is to be performed when clicking on the canvas */
       
    23     _CLICKMODE_ADDNODE = 1,
       
    24     _CLICKMODE_STARTEDGE = 2,
       
    25     _CLICKMODE_ENDEDGE = 3,
       
    26     /* Node size step: Used to calculate the size change when clicking the +/- buttons */
       
    27     _NODE_SIZE_STEP = Math.LN2/4,
       
    28     _MIN_SCALE = 1/20,
       
    29     _MAX_SCALE = 20,
       
    30     _MOUSEMOVE_RATE = 80,
       
    31     _DOUBLETAP_DELAY = 800,
       
    32     /* Maximum distance in pixels (squared, to reduce calculations)
       
    33      * between two taps when double-tapping on a touch terminal */
       
    34     _DOUBLETAP_DISTANCE = 20*20,
       
    35     /* A placeholder so a default colour is displayed when a node has a null value for its user property */
       
    36     _USER_PLACEHOLDER = function(_renkan) {
       
    37         return {
       
    38             color: _renkan.options.default_user_color,
       
    39             title: _renkan.translate("(unknown user)"),
       
    40             get: function(attr) {
       
    41                 return this[attr] || false;
       
    42             }
       
    43         };
       
    44     },
       
    45     /* The code for the "Drag and Add Bookmarklet", slightly minified and with whitespaces removed, though
       
    46      * it doesn't seem that it's still a requirement in newer browsers (i.e. the ones compatibles with canvas drawing)
       
    47      */
       
    48     _BOOKMARKLET_CODE = function(_renkan) {
       
    49         return "(function(a,b,c,d,e,f,h,i,j,k,l,m,n,o,p,q,r){a=document;b=a.body;c=a.location.href;j='draggable';m='text/x-iri-';d=a.createElement('div');d.innerHTML='<p_style=\"position:fixed;top:0;right:0;font:bold_18px_sans-serif;color:#fff;background:#909;padding:10px;z-index:100000;\">"
       
    50         + _renkan.translate("Drag items from this website, drop them in Renkan").replace(/ /g,"_")
       
    51         + "</p>'.replace(/_/g,String.fromCharCode(32));b.appendChild(d);e=[{r:/https?:\\/\\/[^\\/]*twitter\\.com\\//,s:'.tweet',n:'twitter'},{r:/https?:\\/\\/[^\\/]*google\\.[^\\/]+\\//,s:'.g',n:'google'},{r:/https?:\\/\\/[^\\/]*lemonde\\.fr\\//,s:'[data-vr-contentbox]',n:'lemonde'}];f=false;e.forEach(function(g){if(g.r.test(c)){f=g;}});if(f){h=function(){Array.prototype.forEach.call(a.querySelectorAll(f.s),function(i){i[j]=true;k=i.style;k.borderWidth='2px';k.borderColor='#909';k.borderStyle='solid';k.backgroundColor='rgba(200,0,180,.1)';})};window.setInterval(h,500);h();};a.addEventListener('dragstart',function(k){l=k.dataTransfer;l.setData(m+'source-uri',c);l.setData(m+'source-title',a.title);n=k.target;if(f){o=n;while(!o.attributes[j]){o=o.parentNode;if(o==b){break;}}}if(f&&o.attributes[j]){p=o.cloneNode(true);l.setData(m+'specific-site',f.n)}else{q=a.getSelection();if(q.type==='Range'||!q.type){p=q.getRangeAt(0).cloneContents();}else{p=n.cloneNode();}}r=a.createElement('div');r.appendChild(p);l.setData('text/x-iri-selected-text',r.textContent.trim());l.setData('text/x-iri-selected-html',r.innerHTML);},false);})();";
       
    52     },
       
    53     /* Shortens text to the required length then adds ellipsis */
       
    54     shortenText = function(_text, _maxlength) {
       
    55         return (_text.length > _maxlength ? (_text.substr(0,_maxlength) + '…') : _text);
       
    56     },
       
    57     /* Drawing an edit box with an arrow and positioning the edit box according to the position of the node/edge being edited
       
    58      * Called by Rkns.Renderer.NodeEditor and Rkns.Renderer.EdgeEditor */
       
    59     drawEditBox = function(_options, _coords, _path, _xmargin, _selector) {
       
    60         _selector.css({
       
    61             width: ( _options.tooltip_width - 2* _options.tooltip_padding )
       
    62         });
       
    63         var _height = _selector.outerHeight() + 2* _options.tooltip_padding,
       
    64         _isLeft = (_coords.x < paper.view.center.x ? 1 : -1),
       
    65         _left = _coords.x + _isLeft * ( _xmargin + _options.tooltip_arrow_length ),
       
    66         _right = _coords.x + _isLeft * ( _xmargin + _options.tooltip_arrow_length + _options.tooltip_width ),
       
    67         _top = _coords.y - _height / 2;
       
    68         if (_top + _height > (paper.view.size.height - _options.tooltip_margin)) {
       
    69             _top = Math.max( paper.view.size.height - _options.tooltip_margin, _coords.y + _options.tooltip_arrow_width / 2 ) - _height;
       
    70         }
       
    71         if (_top < _options.tooltip_margin) {
       
    72             _top = Math.min( _options.tooltip_margin, _coords.y - _options.tooltip_arrow_width / 2 );
       
    73         }
       
    74         var _bottom = _top + _height;
       
    75         _path.segments[0].point
       
    76         = _path.segments[7].point
       
    77         = _coords.add([_isLeft * _xmargin, 0]);
       
    78         _path.segments[1].point.x
       
    79         = _path.segments[2].point.x
       
    80         = _path.segments[5].point.x
       
    81         = _path.segments[6].point.x
       
    82         = _left;
       
    83         _path.segments[3].point.x
       
    84         = _path.segments[4].point.x
       
    85         = _right;
       
    86         _path.segments[2].point.y
       
    87         = _path.segments[3].point.y
       
    88         = _top;
       
    89         _path.segments[4].point.y
       
    90         = _path.segments[5].point.y
       
    91         = _bottom;
       
    92         _path.segments[1].point.y = _coords.y - _options.tooltip_arrow_width / 2;
       
    93         _path.segments[6].point.y = _coords.y + _options.tooltip_arrow_width / 2;
       
    94         _path.closed = true;
       
    95         _path.fillColor = new paper.GradientColor(new paper.Gradient([_options.tooltip_top_color, _options.tooltip_bottom_color]), [0,_top], [0, _bottom]);
       
    96         _selector.css({
       
    97             left: (_options.tooltip_padding + Math.min(_left, _right)),
       
    98             top: (_options.tooltip_padding + _top)
       
    99         });
       
   100         return _path;
       
   101     };
       
   102 
    15 
   103     /* Rkns.Renderer._BaseRepresentation Class */
    16     /* Rkns.Renderer._BaseRepresentation Class */
   104 
    17 
   105     /* In Renkan, a "Representation" is a sort of ViewModel (in the MVVM paradigm) and bridges the gap between
    18     /* In Renkan, a "Representation" is a sort of ViewModel (in the MVVM paradigm) and bridges the gap between
   106      * models (written with Backbone.js) and the view (written with Paper.js)
    19      * models (written with Backbone.js) and the view (written with Paper.js)
   259                 this.renderer.minimap.node_group.addChild(this.minimap_circle);
   172                 this.renderer.minimap.node_group.addChild(this.minimap_circle);
   260             }
   173             }
   261         },
   174         },
   262         redraw: function(_dontRedrawEdges) {
   175         redraw: function(_dontRedrawEdges) {
   263             var _model_coords = new paper.Point(this.model.get("position")),
   176             var _model_coords = new paper.Point(this.model.get("position")),
   264             _baseRadius = this.options.node_size_base * Math.exp((this.model.get("size") || 0) * _NODE_SIZE_STEP);
   177             _baseRadius = this.options.node_size_base * Math.exp((this.model.get("size") || 0) * Rkns.Utils._NODE_SIZE_STEP);
   265             if (!this.is_dragging || !this.paper_coords) {
   178             if (!this.is_dragging || !this.paper_coords) {
   266                 this.paper_coords = this.renderer.toPaperCoords(_model_coords);
   179                 this.paper_coords = this.renderer.toPaperCoords(_model_coords);
   267             }
   180             }
   268             this.circle_radius = _baseRadius * this.renderer.scale;
   181             this.circle_radius = _baseRadius * this.renderer.scale;
   269             if (this.last_circle_radius !== this.circle_radius) {
   182             if (this.last_circle_radius !== this.circle_radius) {
   312             this.circle.fillColor = this.highlighted ? this.options.highlighted_node_fill_color : this.options.node_fill_color;
   225             this.circle.fillColor = this.highlighted ? this.options.highlighted_node_fill_color : this.options.node_fill_color;
   313 
   226 
   314             this.circle.opacity = this.options.show_node_circles ? opacity : .01;
   227             this.circle.opacity = this.options.show_node_circles ? opacity : .01;
   315 
   228 
   316             var _text = this.model.get("title") || this.renkan.translate(this.options.label_untitled_nodes) || "";
   229             var _text = this.model.get("title") || this.renkan.translate(this.options.label_untitled_nodes) || "";
   317             _text = shortenText(_text, this.options.node_label_max_length);
   230             _text = Rkns.Utils.shortenText(_text, this.options.node_label_max_length);
   318 
   231 
   319             if (typeof this.highlighted === "object") {
   232             if (typeof this.highlighted === "object") {
   320                 this.title.html(this.highlighted.replace(_(_text).escape(),'<span class="Rk-Highlighted">$1</span>'));
   233                 this.title.html(this.highlighted.replace(_(_text).escape(),'<span class="Rk-Highlighted">$1</span>'));
   321             } else {
   234             } else {
   322                 this.title.text(_text);
   235                 this.title.text(_text);
   325             this.title.css({
   238             this.title.css({
   326                 left: this.paper_coords.x,
   239                 left: this.paper_coords.x,
   327                 top: this.paper_coords.y + this.circle_radius * this.h_ratio + this.options.node_label_distance,
   240                 top: this.paper_coords.y + this.circle_radius * this.h_ratio + this.options.node_label_distance,
   328                 opacity: opacity
   241                 opacity: opacity
   329             });
   242             });
   330             var _color = this.model.get("color") || (this.model.get("created_by") || _USER_PLACEHOLDER(this.renkan)).get("color");
   243             var _color = this.model.get("color") || (this.model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(this.renkan)).get("color");
   331             this.circle.strokeColor = _color;
   244             this.circle.strokeColor = _color;
   332             var _pc = this.paper_coords;
   245             var _pc = this.paper_coords;
   333             this.all_buttons.forEach(function(b) {
   246             this.all_buttons.forEach(function(b) {
   334                 b.moveTo(_pc);
   247                 b.moveTo(_pc);
   335             });
   248             });
   692             _p0b = _p0a.add(_delta), /* Adding a 4 px difference */
   605             _p0b = _p0a.add(_delta), /* Adding a 4 px difference */
   693             _p1b = _p1a.add(_delta), /* to differentiate bundled links */
   606             _p1b = _p1a.add(_delta), /* to differentiate bundled links */
   694             _a = _v.angle,
   607             _a = _v.angle,
   695             _textdelta = _ortho.multiply(this.options.edge_label_distance),
   608             _textdelta = _ortho.multiply(this.options.edge_label_distance),
   696             _handle = _v.divide(3),
   609             _handle = _v.divide(3),
   697             _color = this.model.get("color") || this.model.get("color") || (this.model.get("created_by") || _USER_PLACEHOLDER(this.renkan)).get("color"),
   610             _color = this.model.get("color") || this.model.get("color") || (this.model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(this.renkan)).get("color"),
   698             opacity = 1;
   611             opacity = 1;
   699 
   612 
   700             if (this.model.get("delete_scheduled") || this.from_representation.model.get("delete_scheduled") || this.to_representation.model.get("delete_scheduled")) {
   613             if (this.model.get("delete_scheduled") || this.from_representation.model.get("delete_scheduled") || this.to_representation.model.get("delete_scheduled")) {
   701                 opacity = .5;
   614                 opacity = .5;
   702                 this.line.dashArray = [2, 2];
   615                 this.line.dashArray = [2, 2];
   738             if (_a < -90) {
   651             if (_a < -90) {
   739                 _a += 180;
   652                 _a += 180;
   740                 _textdelta = _textdelta.multiply(-1);
   653                 _textdelta = _textdelta.multiply(-1);
   741             }
   654             }
   742             var _text = this.model.get("title") || this.renkan.translate(this.options.label_untitled_edges) || "";
   655             var _text = this.model.get("title") || this.renkan.translate(this.options.label_untitled_edges) || "";
   743             _text = shortenText(_text, this.options.node_label_max_length);
   656             _text = Rkns.Utils.shortenText(_text, this.options.node_label_max_length);
   744             this.text.text(_text);
   657             this.text.text(_text);
   745             var _textpos = this.paper_coords.add(_textdelta);
   658             var _textpos = this.paper_coords.add(_textdelta);
   746             this.text.css({
   659             this.text.css({
   747                 left: _textpos.x,
   660                 left: _textpos.x,
   748                 top: _textpos.y,
   661                 top: _textpos.y,
   851     _(TempEdge.prototype).extend({
   764     _(TempEdge.prototype).extend({
   852         _init: function() {
   765         _init: function() {
   853             this.renderer.edge_layer.activate();
   766             this.renderer.edge_layer.activate();
   854             this.type = "Temp-edge";
   767             this.type = "Temp-edge";
   855 
   768 
   856             var _color = (this.project.get("users").get(this.renkan.current_user) || _USER_PLACEHOLDER(this.renkan)).get("color");
   769             var _color = (this.project.get("users").get(this.renkan.current_user) || Rkns.Utils._USER_PLACEHOLDER(this.renkan)).get("color");
   857             this.line = new paper.Path();
   770             this.line = new paper.Path();
   858             this.line.strokeColor = _color;
   771             this.line.strokeColor = _color;
   859             this.line.dashArray = [4, 2];
   772             this.line.dashArray = [4, 2];
   860             this.line.strokeWidth = this.options.selected_edge_stroke_width;
   773             this.line.strokeWidth = this.options.selected_edge_stroke_width;
   861             this.line.add([0,0],[0,0]);
   774             this.line.add([0,0],[0,0]);
   986                 + '<% if (node.image && options.show_node_tooltip_image) { %><img class="Rk-Display-ImgPreview" src="<%-node.image%>" /><% } %>'
   899                 + '<% if (node.image && options.show_node_tooltip_image) { %><img class="Rk-Display-ImgPreview" src="<%-node.image%>" /><% } %>'
   987                 + '<% if (node.has_creator && options.show_node_tooltip_creator) { %><p><span class="Rk-Editor-Label"><%-renkan.translate("Created by:")%></span><span class="Rk-UserColor" style="background:<%-node.created_by_color%>;"></span><%- shortenText(node.created_by_title, 25) %></p><% } %>'
   900                 + '<% if (node.has_creator && options.show_node_tooltip_creator) { %><p><span class="Rk-Editor-Label"><%-renkan.translate("Created by:")%></span><span class="Rk-UserColor" style="background:<%-node.created_by_color%>;"></span><%- shortenText(node.created_by_title, 25) %></p><% } %>'
   988         ),
   901         ),
   989         draw: function() {
   902         draw: function() {
   990             var _model = this.source_representation.model,
   903             var _model = this.source_representation.model,
   991             _created_by = _model.get("created_by") || _USER_PLACEHOLDER(this.renkan),
   904             _created_by = _model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(this.renkan),
   992             _template = (this.renderer.isEditable() ? this.template : this.readOnlyTemplate ),
   905             _template = (this.renderer.isEditable() ? this.template : this.readOnlyTemplate ),
   993             _image_placeholder = this.options.static_url + "img/image-placeholder.png",
   906             _image_placeholder = this.options.static_url + "img/image-placeholder.png",
   994             _size = (_model.get("size") || 0);
   907             _size = (_model.get("size") || 0);
   995             this.editor_$
   908             this.editor_$
   996             .html(_template({
   909             .html(_template({
   997                 node: {
   910                 node: {
   998                     has_creator: !!_model.get("created_by"),
   911                     has_creator: !!_model.get("created_by"),
   999                     title: _model.get("title"),
   912                     title: _model.get("title"),
  1000                     uri: _model.get("uri"),
   913                     uri: _model.get("uri"),
  1001                     short_uri:  shortenText((_model.get("uri") || "").replace(/^(https?:\/\/)?(www\.)?/,'').replace(/\/$/,''),40),
   914                     short_uri:  Rkns.Utils.shortenText((_model.get("uri") || "").replace(/^(https?:\/\/)?(www\.)?/,'').replace(/\/$/,''),40),
  1002                     description: _model.get("description"),
   915                     description: _model.get("description"),
  1003                     image: _model.get("image") || "",
   916                     image: _model.get("image") || "",
  1004                     image_placeholder: _image_placeholder,
   917                     image_placeholder: _image_placeholder,
  1005                     color: _model.get("color") || _created_by.get("color"),
   918                     color: _model.get("color") || _created_by.get("color"),
  1006                     clip_path: _model.get("clip_path") || false,
   919                     clip_path: _model.get("clip_path") || false,
  1008                     created_by_title: _created_by.get("title"),
   921                     created_by_title: _created_by.get("title"),
  1009                     size: (_size > 0 ? "+" : "") + _size
   922                     size: (_size > 0 ? "+" : "") + _size
  1010                 },
   923                 },
  1011                 renkan: this.renkan,
   924                 renkan: this.renkan,
  1012                 options: this.options,
   925                 options: this.options,
  1013                 shortenText: shortenText
   926                 shortenText: Rkns.Utils.shortenText
  1014             }));
   927             }));
  1015             this.redraw();
   928             this.redraw();
  1016             var _this = this,
   929             var _this = this,
  1017             closeEditor = function() {
   930             closeEditor = function() {
  1018                 _this.renderer.removeRepresentation(_this);
   931                 _this.renderer.removeRepresentation(_this);
  1102                             _e.preventDefault();
  1015                             _e.preventDefault();
  1103                             _this.editor_$.find(".Rk-Edit-Color").css("background", $(this).attr("data-color"));
  1016                             _this.editor_$.find(".Rk-Edit-Color").css("background", $(this).attr("data-color"));
  1104                         },
  1017                         },
  1105                         function(_e) {
  1018                         function(_e) {
  1106                             _e.preventDefault();
  1019                             _e.preventDefault();
  1107                             _this.editor_$.find(".Rk-Edit-Color").css("background", _model.get("color") || (_model.get("created_by") || _USER_PLACEHOLDER(_this.renkan)).get("color"));
  1020                             _this.editor_$.find(".Rk-Edit-Color").css("background", _model.get("color") || (_model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(_this.renkan)).get("color"));
  1108                         }
  1021                         }
  1109                 ).click(function(_e) {
  1022                 ).click(function(_e) {
  1110                     _e.preventDefault();
  1023                     _e.preventDefault();
  1111                     if (_this.renderer.isEditable()) {
  1024                     if (_this.renderer.isEditable()) {
  1112                         _model.set("color", $(this).attr("data-color"));
  1025                         _model.set("color", $(this).attr("data-color"));
  1149                 _this.redraw();
  1062                 _this.redraw();
  1150             });
  1063             });
  1151         },
  1064         },
  1152         redraw: function() {
  1065         redraw: function() {
  1153             var _coords = this.source_representation.paper_coords;
  1066             var _coords = this.source_representation.paper_coords;
  1154             drawEditBox(this.options, _coords, this.editor_block, this.source_representation.circle_radius * .75, this.editor_$);
  1067             Rkns.Utils.drawEditBox(this.options, _coords, this.editor_block, this.source_representation.circle_radius * .75, this.editor_$);
  1155             this.editor_$.show();
  1068             this.editor_$.show();
  1156             paper.view.draw();
  1069             paper.view.draw();
  1157         }
  1070         }
  1158     });
  1071     });
  1159 
  1072 
  1189         ),
  1102         ),
  1190         draw: function() {
  1103         draw: function() {
  1191             var _model = this.source_representation.model,
  1104             var _model = this.source_representation.model,
  1192             _from_model = _model.get("from"),
  1105             _from_model = _model.get("from"),
  1193             _to_model = _model.get("to"),
  1106             _to_model = _model.get("to"),
  1194             _created_by = _model.get("created_by") || _USER_PLACEHOLDER(this.renkan),
  1107             _created_by = _model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(this.renkan),
  1195             _template = (this.renderer.isEditable() ? this.template : this.readOnlyTemplate);
  1108             _template = (this.renderer.isEditable() ? this.template : this.readOnlyTemplate);
  1196             this.editor_$
  1109             this.editor_$
  1197             .html(_template({
  1110             .html(_template({
  1198                 edge: {
  1111                 edge: {
  1199                     has_creator: !!_model.get("created_by"),
  1112                     has_creator: !!_model.get("created_by"),
  1200                     title: _model.get("title"),
  1113                     title: _model.get("title"),
  1201                     uri: _model.get("uri"),
  1114                     uri: _model.get("uri"),
  1202                     short_uri:  shortenText((_model.get("uri") || "").replace(/^(https?:\/\/)?(www\.)?/,'').replace(/\/$/,''),40),
  1115                     short_uri:  Rkns.Utils.shortenText((_model.get("uri") || "").replace(/^(https?:\/\/)?(www\.)?/,'').replace(/\/$/,''),40),
  1203                     description: _model.get("description"),
  1116                     description: _model.get("description"),
  1204                     color: _model.get("color") || _created_by.get("color"),
  1117                     color: _model.get("color") || _created_by.get("color"),
  1205                     from_title: _from_model.get("title"),
  1118                     from_title: _from_model.get("title"),
  1206                     to_title: _to_model.get("title"),
  1119                     to_title: _to_model.get("title"),
  1207                     from_color: _from_model.get("color") || (_from_model.get("created_by") || _USER_PLACEHOLDER(this.renkan)).get("color"),
  1120                     from_color: _from_model.get("color") || (_from_model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(this.renkan)).get("color"),
  1208                     to_color: _to_model.get("color") || (_to_model.get("created_by") || _USER_PLACEHOLDER(this.renkan)).get("color"),
  1121                     to_color: _to_model.get("color") || (_to_model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(this.renkan)).get("color"),
  1209                     created_by_color: _created_by.get("color"),
  1122                     created_by_color: _created_by.get("color"),
  1210                     created_by_title: _created_by.get("title")
  1123                     created_by_title: _created_by.get("title")
  1211                 },
  1124                 },
  1212                 renkan: this.renkan,
  1125                 renkan: this.renkan,
  1213                 shortenText: shortenText,
  1126                 shortenText: Rkns.Utils.shortenText,
  1214                 options: this.options
  1127                 options: this.options
  1215             }));
  1128             }));
  1216             this.redraw();
  1129             this.redraw();
  1217             var _this = this,
  1130             var _this = this,
  1218             closeEditor = function() {
  1131             closeEditor = function() {
  1293                             _e.preventDefault();
  1206                             _e.preventDefault();
  1294                             _this.editor_$.find(".Rk-Edit-Color").css("background", $(this).attr("data-color"));
  1207                             _this.editor_$.find(".Rk-Edit-Color").css("background", $(this).attr("data-color"));
  1295                         },
  1208                         },
  1296                         function(_e) {
  1209                         function(_e) {
  1297                             _e.preventDefault();
  1210                             _e.preventDefault();
  1298                             _this.editor_$.find(".Rk-Edit-Color").css("background", _model.get("color") || (_model.get("created_by") || _USER_PLACEHOLDER(_this.renkan)).get("color"));
  1211                             _this.editor_$.find(".Rk-Edit-Color").css("background", _model.get("color") || (_model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(_this.renkan)).get("color"));
  1299                         }
  1212                         }
  1300                 ).click(function(_e) {
  1213                 ).click(function(_e) {
  1301                     _e.preventDefault();
  1214                     _e.preventDefault();
  1302                     if (_this.renderer.isEditable()) {
  1215                     if (_this.renderer.isEditable()) {
  1303                         _model.set("color", $(this).attr("data-color"));
  1216                         _model.set("color", $(this).attr("data-color"));
  1309                 });
  1222                 });
  1310             }
  1223             }
  1311         },
  1224         },
  1312         redraw: function() {
  1225         redraw: function() {
  1313             var _coords = this.source_representation.paper_coords;
  1226             var _coords = this.source_representation.paper_coords;
  1314             drawEditBox(this.options, _coords, this.editor_block, 5, this.editor_$);
  1227             Rkns.Utils.drawEditBox(this.options, _coords, this.editor_block, 5, this.editor_$);
  1315             this.editor_$.show();
  1228             this.editor_$.show();
  1316             paper.view.draw();
  1229             paper.view.draw();
  1317         }
  1230         }
  1318     });
  1231     });
  1319 
  1232 
  1328                 if (this.sector) {
  1241                 if (this.sector) {
  1329                     this.sector.destroy();
  1242                     this.sector.destroy();
  1330                 }
  1243                 }
  1331                 this.sector = this.renderer.drawSector(
  1244                 this.sector = this.renderer.drawSector(
  1332                         this, 1 + sectorInner,
  1245                         this, 1 + sectorInner,
  1333                         _NODE_BUTTON_WIDTH + sectorInner,
  1246                         Rkns.Utils._NODE_BUTTON_WIDTH + sectorInner,
  1334                         this.startAngle,
  1247                         this.startAngle,
  1335                         this.endAngle,
  1248                         this.endAngle,
  1336                         1,
  1249                         1,
  1337                         this.imageName,
  1250                         this.imageName,
  1338                         this.renkan.translate(this.text)
  1251                         this.renkan.translate(this.text)
  1494     var EdgeEditButton = Renderer.EdgeEditButton = Rkns.Utils.inherit(_BaseButton);
  1407     var EdgeEditButton = Renderer.EdgeEditButton = Rkns.Utils.inherit(_BaseButton);
  1495 
  1408 
  1496     _(EdgeEditButton.prototype).extend({
  1409     _(EdgeEditButton.prototype).extend({
  1497         _init: function() {
  1410         _init: function() {
  1498             this.type = "Edge-edit-button";
  1411             this.type = "Edge-edit-button";
  1499             this.sector = this.renderer.drawSector(this, _EDGE_BUTTON_INNER, _EDGE_BUTTON_OUTER, -270, -90, 1, "edit", this.renkan.translate("Edit"));
  1412             this.sector = this.renderer.drawSector(this, Rkns.Utils._EDGE_BUTTON_INNER, Rkns.Utils._EDGE_BUTTON_OUTER, -270, -90, 1, "edit", this.renkan.translate("Edit"));
  1500         },
  1413         },
  1501         mouseup: function() {
  1414         mouseup: function() {
  1502             if (!this.renderer.is_dragging) {
  1415             if (!this.renderer.is_dragging) {
  1503                 this.source_representation.openEditor();
  1416                 this.source_representation.openEditor();
  1504             }
  1417             }
  1510     var EdgeRemoveButton = Renderer.EdgeRemoveButton = Rkns.Utils.inherit(_BaseButton);
  1423     var EdgeRemoveButton = Renderer.EdgeRemoveButton = Rkns.Utils.inherit(_BaseButton);
  1511 
  1424 
  1512     _(EdgeRemoveButton.prototype).extend({
  1425     _(EdgeRemoveButton.prototype).extend({
  1513         _init: function() {
  1426         _init: function() {
  1514             this.type = "Edge-remove-button";
  1427             this.type = "Edge-remove-button";
  1515             this.sector = this.renderer.drawSector(this, _EDGE_BUTTON_INNER, _EDGE_BUTTON_OUTER, -90, 90, 1, "remove", this.renkan.translate("Remove"));
  1428             this.sector = this.renderer.drawSector(this, Rkns.Utils._EDGE_BUTTON_INNER, Rkns.Utils._EDGE_BUTTON_OUTER, -90, 90, 1, "remove", this.renkan.translate("Remove"));
  1516         },
  1429         },
  1517         mouseup: function() {
  1430         mouseup: function() {
  1518             this.renderer.click_target = null;
  1431             this.renderer.click_target = null;
  1519             this.renderer.is_dragging = false;
  1432             this.renderer.is_dragging = false;
  1520             this.renderer.removeRepresentationsOfType("editor");
  1433             this.renderer.removeRepresentationsOfType("editor");
  1540     var EdgeRevertButton = Renderer.EdgeRevertButton = Rkns.Utils.inherit(_BaseButton);
  1453     var EdgeRevertButton = Renderer.EdgeRevertButton = Rkns.Utils.inherit(_BaseButton);
  1541 
  1454 
  1542     _(EdgeRevertButton.prototype).extend({
  1455     _(EdgeRevertButton.prototype).extend({
  1543         _init: function() {
  1456         _init: function() {
  1544             this.type = "Edge-revert-button";
  1457             this.type = "Edge-revert-button";
  1545             this.sector = this.renderer.drawSector(this, _EDGE_BUTTON_INNER, _EDGE_BUTTON_OUTER, -135, 135, 1, "revert", this.renkan.translate("Cancel deletion"));
  1458             this.sector = this.renderer.drawSector(this, Rkns.Utils._EDGE_BUTTON_INNER, Rkns.Utils._EDGE_BUTTON_OUTER, -135, 135, 1, "revert", this.renkan.translate("Cancel deletion"));
  1546         },
  1459         },
  1547         mouseup: function() {
  1460         mouseup: function() {
  1548             this.renderer.click_target = null;
  1461             this.renderer.click_target = null;
  1549             this.renderer.is_dragging = false;
  1462             this.renderer.is_dragging = false;
  1550             if (this.renderer.isEditable()) {
  1463             if (this.renderer.isEditable()) {
  1644         ['edit', 'remove', 'link', 'enlarge', 'shrink', 'revert' ].forEach(function(imgname) {
  1557         ['edit', 'remove', 'link', 'enlarge', 'shrink', 'revert' ].forEach(function(imgname) {
  1645             var img = new Image();
  1558             var img = new Image();
  1646             img.src = _renkan.options.static_url + 'img/' + imgname + '.png';
  1559             img.src = _renkan.options.static_url + 'img/' + imgname + '.png';
  1647             _this.icon_cache[imgname] = img;
  1560             _this.icon_cache[imgname] = img;
  1648         });
  1561         });
  1649 
  1562         
  1650         var throttledMouseMove = _.throttle(function(_event, _isTouch) {
  1563         var throttledMouseMove = _.throttle(function(_event, _isTouch) {
  1651             _this.onMouseMove(_event, _isTouch);
  1564             _this.onMouseMove(_event, _isTouch);
  1652         }, _MOUSEMOVE_RATE);
  1565         }, Rkns.Utils._MOUSEMOVE_RATE);
  1653 
  1566 
  1654         this.canvas_$.on({
  1567         this.canvas_$.on({
  1655             mousedown: function(_event) {
  1568             mousedown: function(_event) {
  1656                 _event.preventDefault();
  1569                 _event.preventDefault();
  1657                 _this.onMouseDown(_event, false);
  1570                 _this.onMouseDown(_event, false);
  1675             touchstart: function(_event) {
  1588             touchstart: function(_event) {
  1676                 _event.preventDefault();
  1589                 _event.preventDefault();
  1677                 var _touches = _event.originalEvent.touches[0];
  1590                 var _touches = _event.originalEvent.touches[0];
  1678                 if (
  1591                 if (
  1679                         _renkan.options.allow_double_click
  1592                         _renkan.options.allow_double_click
  1680                         && new Date() - _lastTap < _DOUBLETAP_DELAY
  1593                         && new Date() - _lastTap < Rkns.Utils._DOUBLETAP_DELAY
  1681                         && ( Math.pow(_lastTapX - _touches.pageX, 2) + Math.pow(_lastTapY - _touches.pageY, 2) < _DOUBLETAP_DISTANCE )
  1594                         && ( Math.pow(_lastTapX - _touches.pageX, 2) + Math.pow(_lastTapY - _touches.pageY, 2) < Rkns.Utils._DOUBLETAP_DISTANCE )
  1682                 ) {
  1595                 ) {
  1683                     _lastTap = 0;
  1596                     _lastTap = 0;
  1684                     _this.onDoubleClick(_touches);
  1597                     _this.onDoubleClick(_touches);
  1685                 } else {
  1598                 } else {
  1686                     _lastTap = new Date();
  1599                     _lastTap = new Date();
  1818         bindClick(".Rk-AddNode-Button", "addNodeBtn");
  1731         bindClick(".Rk-AddNode-Button", "addNodeBtn");
  1819         bindClick(".Rk-AddEdge-Button", "addEdgeBtn");
  1732         bindClick(".Rk-AddEdge-Button", "addEdgeBtn");
  1820         bindClick(".Rk-Save-Button", "save");
  1733         bindClick(".Rk-Save-Button", "save");
  1821         bindClick(".Rk-Open-Button", "open");
  1734         bindClick(".Rk-Open-Button", "open");
  1822         this.$.find(".Rk-Bookmarklet-Button")
  1735         this.$.find(".Rk-Bookmarklet-Button")
  1823         .attr("href","javascript:" + _BOOKMARKLET_CODE(_renkan))
  1736         .attr("href","javascript:" + Rkns.Utils._BOOKMARKLET_CODE(_renkan))
  1824         .click(function(){
  1737         .click(function(){
  1825             _this.notif_$
  1738             _this.notif_$
  1826             .text(_renkan.translate("Drag this button to your bookmark bar. When on a third-party website, click it to enable drag-and-drop from the website to Renkan."))
  1739             .text(_renkan.translate("Drag this button to your bookmark bar. When on a third-party website, click it to enable drag-and-drop from the website to Renkan."))
  1827             .fadeIn()
  1740             .fadeIn()
  1828             .delay(5000)
  1741             .delay(5000)
  2199                 }
  2112                 }
  2200             }
  2113             }
  2201             this.redrawUsers();
  2114             this.redrawUsers();
  2202         },
  2115         },
  2203         setScale: function(_newScale, _offset) {
  2116         setScale: function(_newScale, _offset) {
  2204             if ((_newScale/this.initialScale) > _MIN_SCALE && (_newScale/this.initialScale) < _MAX_SCALE) {
  2117             if ((_newScale/this.initialScale) > Rkns.Utils._MIN_SCALE && (_newScale/this.initialScale) < Rkns.Utils._MAX_SCALE) {
  2205                 this.scale = _newScale;
  2118                 this.scale = _newScale;
  2206                 if (_offset) {
  2119                 if (_offset) {
  2207                     this.offset = _offset;
  2120                     this.offset = _offset;
  2208                 }
  2121                 }
  2209                 this.redraw();
  2122                 this.redraw();
  2270         toModelCoords: function(_point) {
  2183         toModelCoords: function(_point) {
  2271             return _point.subtract(this.offset).divide(this.scale);
  2184             return _point.subtract(this.offset).divide(this.scale);
  2272         },
  2185         },
  2273         addRepresentation: function(_type, _model) {
  2186         addRepresentation: function(_type, _model) {
  2274             var _repr = new Renderer[_type](this, _model);
  2187             var _repr = new Renderer[_type](this, _model);
       
  2188             console.log("REPR RENKAN",_repr);
       
  2189             console.log("REPR RENKAN",Renderer[_type]);
  2275             this.representations.push(_repr);
  2190             this.representations.push(_repr);
  2276             return _repr;
  2191             return _repr;
  2277         },
  2192         },
  2278         addRepresentations: function(_type, _collection) {
  2193         addRepresentations: function(_type, _collection) {
  2279             var _this = this;
  2194             var _this = this;
  2424                                       _event.pageX - _off.left,
  2339                                       _event.pageX - _off.left,
  2425                                       _event.pageY - _off.top
  2340                                       _event.pageY - _off.top
  2426                                       ]),
  2341                                       ]),
  2427                                       _delta = _point.subtract(this.last_point);
  2342                                       _delta = _point.subtract(this.last_point);
  2428             this.last_point = _point;
  2343             this.last_point = _point;
  2429             if (!this.is_dragging && this.mouse_down && _delta.length > _MIN_DRAG_DISTANCE) {
  2344             if (!this.is_dragging && this.mouse_down && _delta.length > Rkns.Utils._MIN_DRAG_DISTANCE) {
  2430                 this.is_dragging = true;
  2345                 this.is_dragging = true;
  2431             }
  2346             }
  2432             var _hitResult = paper.project.hitTest(_point);
  2347             var _hitResult = paper.project.hitTest(_point);
  2433             if (this.is_dragging) {
  2348             if (this.is_dragging) {
  2434                 if (this.click_target && typeof this.click_target.paperShift === "function") {
  2349                 if (this.click_target && typeof this.click_target.paperShift === "function") {
  2456                 if (_hitResult && typeof _hitResult.item.__representation !== "undefined") {
  2371                 if (_hitResult && typeof _hitResult.item.__representation !== "undefined") {
  2457                     this.click_target = _hitResult.item.__representation;
  2372                     this.click_target = _hitResult.item.__representation;
  2458                     this.click_target.mousedown(_event, _isTouch);
  2373                     this.click_target.mousedown(_event, _isTouch);
  2459                 } else {
  2374                 } else {
  2460                     this.click_target = null;
  2375                     this.click_target = null;
  2461                     if (this.isEditable() && this.click_mode === _CLICKMODE_ADDNODE) {
  2376                     if (this.isEditable() && this.click_mode === Rkns.Utils._CLICKMODE_ADDNODE) {
  2462                         var _coords = this.toModelCoords(_point),
  2377                         var _coords = this.toModelCoords(_point),
  2463                         _data = {
  2378                         _data = {
  2464                             id: Rkns.Utils.getUID('node'),
  2379                             id: Rkns.Utils.getUID('node'),
  2465                             created_by: this.renkan.current_user,
  2380                             created_by: this.renkan.current_user,
  2466                             position: {
  2381                             position: {
  2472                         this.getRepresentationByModel(_node).openEditor();
  2387                         this.getRepresentationByModel(_node).openEditor();
  2473                     }
  2388                     }
  2474                 }
  2389                 }
  2475             }
  2390             }
  2476             if (this.click_mode) {
  2391             if (this.click_mode) {
  2477                 if (this.isEditable() && this.click_mode === _CLICKMODE_STARTEDGE && this.click_target && this.click_target.type === "Node") {
  2392                 if (this.isEditable() && this.click_mode === Rkns.Utils._CLICKMODE_STARTEDGE && this.click_target && this.click_target.type === "Node") {
  2478                     this.removeRepresentationsOfType("editor");
  2393                     this.removeRepresentationsOfType("editor");
  2479                     this.addTempEdge(this.click_target, _point);
  2394                     this.addTempEdge(this.click_target, _point);
  2480                     this.click_mode = _CLICKMODE_ENDEDGE;
  2395                     this.click_mode = Rkns.Utils._CLICKMODE_ENDEDGE;
  2481                     this.notif_$.fadeOut(function() {
  2396                     this.notif_$.fadeOut(function() {
  2482                         $(this).html(this.renkan.translate("Click on a second node to complete the edge")).fadeIn();
  2397                         $(this).html(this.renkan.translate("Click on a second node to complete the edge")).fadeIn();
  2483                     });
  2398                     });
  2484                 } else {
  2399                 } else {
  2485                     this.notif_$.hide();
  2400                     this.notif_$.hide();
  2714                                        this.canvas_$.height()
  2629                                        this.canvas_$.height()
  2715                                        ]).multiply( .5 * ( 1 - Math.SQRT2 ) ).add(this.offset.multiply( Math.SQRT2 ));
  2630                                        ]).multiply( .5 * ( 1 - Math.SQRT2 ) ).add(this.offset.multiply( Math.SQRT2 ));
  2716             this.setScale( _newScale, _offset );
  2631             this.setScale( _newScale, _offset );
  2717         },
  2632         },
  2718         addNodeBtn: function() {
  2633         addNodeBtn: function() {
  2719             if (this.click_mode === _CLICKMODE_ADDNODE) {
  2634             if (this.click_mode === Rkns.Utils._CLICKMODE_ADDNODE) {
  2720                 this.click_mode = false;
  2635                 this.click_mode = false;
  2721                 this.notif_$.hide();
  2636                 this.notif_$.hide();
  2722             } else {
  2637             } else {
  2723                 this.click_mode = _CLICKMODE_ADDNODE;
  2638                 this.click_mode = Rkns.Utils._CLICKMODE_ADDNODE;
  2724                 this.notif_$.text(this.renkan.translate("Click on the background canvas to add a node")).fadeIn();
  2639                 this.notif_$.text(this.renkan.translate("Click on the background canvas to add a node")).fadeIn();
  2725             }
  2640             }
  2726             return false;
  2641             return false;
  2727         },
  2642         },
  2728         addEdgeBtn: function() {
  2643         addEdgeBtn: function() {
  2729             if (this.click_mode === _CLICKMODE_STARTEDGE || this.click_mode === _CLICKMODE_ENDEDGE) {
  2644             if (this.click_mode === Rkns.Utils._CLICKMODE_STARTEDGE || this.click_mode === Rkns.Utils._CLICKMODE_ENDEDGE) {
  2730                 this.click_mode = false;
  2645                 this.click_mode = false;
  2731                 this.notif_$.hide();
  2646                 this.notif_$.hide();
  2732             } else {
  2647             } else {
  2733                 this.click_mode = _CLICKMODE_STARTEDGE;
  2648                 this.click_mode = Rkns.Utils._CLICKMODE_STARTEDGE;
  2734                 this.notif_$.text(this.renkan.translate("Click on a first node to start the edge")).fadeIn();
  2649                 this.notif_$.text(this.renkan.translate("Click on a first node to start the edge")).fadeIn();
  2735             }
  2650             }
  2736             return false;
  2651             return false;
  2737         },
  2652         },
  2738         foldBins: function() {
  2653         foldBins: function() {