1 /* paper-renderer.js */ |
|
2 "use strict"; |
|
3 |
|
4 (function(root) { |
|
5 |
|
6 var Rkns = root.Rkns, |
|
7 _ = Rkns._, |
|
8 $ = Rkns.$; |
|
9 |
|
10 /* Rkns.Renderer Object */ |
|
11 |
|
12 /* This object contains constants, utility functions and classes for Renkan's Graph Manipulation GUI */ |
|
13 |
|
14 var Renderer = Rkns.Renderer = {}; |
|
15 |
|
16 /* Rkns.Renderer._BaseRepresentation Class */ |
|
17 |
|
18 /* In Renkan, a "Representation" is a sort of ViewModel (in the MVVM paradigm) and bridges the gap between |
|
19 * models (written with Backbone.js) and the view (written with Paper.js) |
|
20 * Renkan's representations all inherit from Rkns.Renderer._BaseRepresentation '*/ |
|
21 |
|
22 var _BaseRepresentation = Renderer._BaseRepresentation = function(_renderer, _model) { |
|
23 if (typeof _renderer !== "undefined") { |
|
24 this.renderer = _renderer; |
|
25 this.renkan = _renderer.renkan; |
|
26 this.project = _renderer.renkan.project; |
|
27 this.options = _renderer.renkan.options; |
|
28 this.model = _model; |
|
29 if (this.model) { |
|
30 var _this = this; |
|
31 this._changeBinding = function() { |
|
32 _this.redraw(); |
|
33 }; |
|
34 this._removeBinding = function() { |
|
35 _renderer.removeRepresentation(_this); |
|
36 _(function() { |
|
37 _renderer.redraw(); |
|
38 }).defer(); |
|
39 }; |
|
40 this._selectBinding = function() { |
|
41 _this.select(); |
|
42 }; |
|
43 this._unselectBinding = function() { |
|
44 _this.unselect(); |
|
45 }; |
|
46 this.model.on("change", this._changeBinding ); |
|
47 this.model.on("remove", this._removeBinding ); |
|
48 this.model.on("select", this._selectBinding ); |
|
49 this.model.on("unselect", this._unselectBinding ); |
|
50 } |
|
51 } |
|
52 }; |
|
53 |
|
54 /* Rkns.Renderer._BaseRepresentation Methods */ |
|
55 |
|
56 _(_BaseRepresentation.prototype).extend({ |
|
57 _super: function(_func) { |
|
58 return _BaseRepresentation.prototype[_func].apply(this, Array.prototype.slice.call(arguments, 1)); |
|
59 }, |
|
60 redraw: function() {}, |
|
61 moveTo: function() {}, |
|
62 show: function() {}, |
|
63 hide: function() {}, |
|
64 select: function() { |
|
65 if (this.model) { |
|
66 this.model.trigger("selected"); |
|
67 } |
|
68 }, |
|
69 unselect: function() { |
|
70 if (this.model) { |
|
71 this.model.trigger("unselected"); |
|
72 } |
|
73 }, |
|
74 highlight: function() {}, |
|
75 unhighlight: function() {}, |
|
76 mousedown: function() {}, |
|
77 mouseup: function() { |
|
78 if (this.model) { |
|
79 this.model.trigger("clicked"); |
|
80 } |
|
81 }, |
|
82 destroy: function() { |
|
83 if (this.model) { |
|
84 this.model.off("change", this._changeBinding ); |
|
85 this.model.off("remove", this._removeBinding ); |
|
86 this.model.off("select", this._selectBinding ); |
|
87 this.model.off("unselect", this._unselectBinding ); |
|
88 } |
|
89 } |
|
90 }); |
|
91 |
|
92 /* End of Rkns.Renderer._BaseRepresentation Class */ |
|
93 |
|
94 /* Rkns.Renderer._BaseButton Class */ |
|
95 |
|
96 /* BaseButton is extended by contextual buttons that appear when hovering on nodes and edges */ |
|
97 |
|
98 var _BaseButton = Renderer._BaseButton = Rkns.Utils.inherit(_BaseRepresentation); |
|
99 |
|
100 _(_BaseButton.prototype).extend({ |
|
101 moveTo: function(_pos) { |
|
102 this.sector.moveTo(_pos); |
|
103 }, |
|
104 show: function() { |
|
105 this.sector.show(); |
|
106 }, |
|
107 hide: function() { |
|
108 this.sector.hide(); |
|
109 }, |
|
110 select: function() { |
|
111 this.sector.select(); |
|
112 }, |
|
113 unselect: function(_newTarget) { |
|
114 this.sector.unselect(); |
|
115 if (!_newTarget || (_newTarget !== this.source_representation && _newTarget.source_representation !== this.source_representation)) { |
|
116 this.source_representation.unselect(); |
|
117 } |
|
118 }, |
|
119 destroy: function() { |
|
120 this.sector.destroy(); |
|
121 } |
|
122 }); |
|
123 |
|
124 /* End of Rkns.Renderer._BaseButton Class */ |
|
125 |
|
126 /* Rkns.Renderer.Node Class */ |
|
127 |
|
128 /* The representation for the node : A circle, with an image inside and a text label underneath. |
|
129 * The circle and the image are drawn on canvas and managed by Paper.js. |
|
130 * The text label is an HTML node, managed by jQuery. */ |
|
131 |
|
132 var NodeRepr = Renderer.Node = Rkns.Utils.inherit(_BaseRepresentation); |
|
133 |
|
134 _(NodeRepr.prototype).extend({ |
|
135 _init: function() { |
|
136 this.renderer.node_layer.activate(); |
|
137 this.type = "Node"; |
|
138 this.circle = new paper.Path.Circle([0, 0], 1); |
|
139 this.circle.__representation = this; |
|
140 if (this.options.show_node_circles) { |
|
141 this.circle.strokeWidth = this.options.node_stroke_width; |
|
142 this.h_ratio = 1; |
|
143 } else { |
|
144 this.h_ratio = 0; |
|
145 } |
|
146 this.title = $('<div class="Rk-Label">').appendTo(this.renderer.labels_$); |
|
147 if (this.options.editor_mode) { |
|
148 this.normal_buttons = [ |
|
149 new NodeEditButton(this.renderer, null), |
|
150 new NodeRemoveButton(this.renderer, null), |
|
151 new NodeLinkButton(this.renderer, null), |
|
152 new NodeEnlargeButton(this.renderer, null), |
|
153 new NodeShrinkButton(this.renderer, null) |
|
154 ]; |
|
155 this.pending_delete_buttons = [ |
|
156 new NodeRevertButton(this.renderer, null) |
|
157 ]; |
|
158 this.all_buttons = this.normal_buttons.concat(this.pending_delete_buttons); |
|
159 for (var i = 0; i < this.all_buttons.length; i++) { |
|
160 this.all_buttons[i].source_representation = this; |
|
161 } |
|
162 this.active_buttons = []; |
|
163 } else { |
|
164 this.active_buttons = this.all_buttons = []; |
|
165 } |
|
166 this.last_circle_radius = 1; |
|
167 |
|
168 if (this.renderer.minimap) { |
|
169 this.renderer.minimap.node_layer.activate(); |
|
170 this.minimap_circle = new paper.Path.Circle([0, 0], 1); |
|
171 this.minimap_circle.__representation = this.renderer.minimap.miniframe.__representation; |
|
172 this.renderer.minimap.node_group.addChild(this.minimap_circle); |
|
173 } |
|
174 }, |
|
175 redraw: function(_dontRedrawEdges) { |
|
176 var _model_coords = new paper.Point(this.model.get("position")), |
|
177 _baseRadius = this.options.node_size_base * Math.exp((this.model.get("size") || 0) * Rkns.Utils._NODE_SIZE_STEP); |
|
178 if (!this.is_dragging || !this.paper_coords) { |
|
179 this.paper_coords = this.renderer.toPaperCoords(_model_coords); |
|
180 } |
|
181 this.circle_radius = _baseRadius * this.renderer.scale; |
|
182 if (this.last_circle_radius !== this.circle_radius) { |
|
183 this.all_buttons.forEach(function(b) { |
|
184 b.setSectorSize(); |
|
185 }); |
|
186 this.circle.scale(this.circle_radius / this.last_circle_radius); |
|
187 if (this.node_image) { |
|
188 this.node_image.scale(this.circle_radius / this.last_circle_radius); |
|
189 } |
|
190 } |
|
191 this.circle.position = this.paper_coords; |
|
192 if (this.node_image) { |
|
193 this.node_image.position = this.paper_coords.subtract(this.image_delta.multiply(this.circle_radius)); |
|
194 } |
|
195 this.last_circle_radius = this.circle_radius; |
|
196 |
|
197 var old_act_btn = this.active_buttons; |
|
198 |
|
199 var opacity = 1; |
|
200 if (this.model.get("delete_scheduled")) { |
|
201 opacity = .5; |
|
202 this.active_buttons = this.pending_delete_buttons; |
|
203 this.circle.dashArray = [2,2]; |
|
204 } else { |
|
205 opacity = 1; |
|
206 this.active_buttons = this.normal_buttons; |
|
207 this.circle.dashArray = null; |
|
208 } |
|
209 |
|
210 if (this.selected && this.renderer.isEditable()) { |
|
211 if (old_act_btn !== this.active_buttons) { |
|
212 old_act_btn.forEach(function(b) { |
|
213 b.hide(); |
|
214 }); |
|
215 } |
|
216 this.active_buttons.forEach(function(b) { |
|
217 b.show(); |
|
218 }); |
|
219 } |
|
220 |
|
221 if (this.node_image) { |
|
222 this.node_image.opacity = this.highlighted ? opacity * .5 : (opacity - .01); |
|
223 } |
|
224 |
|
225 this.circle.fillColor = this.highlighted ? this.options.highlighted_node_fill_color : this.options.node_fill_color; |
|
226 |
|
227 this.circle.opacity = this.options.show_node_circles ? opacity : .01; |
|
228 |
|
229 var _text = this.model.get("title") || this.renkan.translate(this.options.label_untitled_nodes) || ""; |
|
230 _text = Rkns.Utils.shortenText(_text, this.options.node_label_max_length); |
|
231 |
|
232 if (typeof this.highlighted === "object") { |
|
233 this.title.html(this.highlighted.replace(_(_text).escape(),'<span class="Rk-Highlighted">$1</span>')); |
|
234 } else { |
|
235 this.title.text(_text); |
|
236 } |
|
237 |
|
238 this.title.css({ |
|
239 left: this.paper_coords.x, |
|
240 top: this.paper_coords.y + this.circle_radius * this.h_ratio + this.options.node_label_distance, |
|
241 opacity: opacity |
|
242 }); |
|
243 var _color = this.model.get("color") || (this.model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(this.renkan)).get("color"); |
|
244 this.circle.strokeColor = _color; |
|
245 var _pc = this.paper_coords; |
|
246 this.all_buttons.forEach(function(b) { |
|
247 b.moveTo(_pc); |
|
248 }); |
|
249 var lastImage = this.img; |
|
250 this.img = this.model.get("image"); |
|
251 if (this.img && this.img !== lastImage) { |
|
252 this.showImage(); |
|
253 } |
|
254 if (this.node_image && !this.img) { |
|
255 this.node_image.remove(); |
|
256 delete this.node_image; |
|
257 } |
|
258 |
|
259 if (this.renderer.minimap) { |
|
260 this.minimap_circle.fillColor = _color; |
|
261 var minipos = this.renderer.toMinimapCoords(_model_coords), |
|
262 miniradius = this.renderer.minimap.scale * _baseRadius, |
|
263 minisize = new paper.Size([miniradius, miniradius]); |
|
264 this.minimap_circle.fitBounds(minipos.subtract(minisize), minisize.multiply(2)); |
|
265 } |
|
266 |
|
267 if (!_dontRedrawEdges) { |
|
268 var _this = this; |
|
269 _.each( |
|
270 this.project.get("edges").filter( |
|
271 function (ed) { |
|
272 return ((ed.get("to") === _this.model) || (ed.get("from") === _this.model)); |
|
273 } |
|
274 ), |
|
275 function(edge, index, list) { |
|
276 var repr = _this.renderer.getRepresentationByModel(edge); |
|
277 if (repr && typeof repr.from_representation !== "undefined" && typeof repr.from_representation.paper_coords !== "undefined" && typeof repr.to_representation !== "undefined" && typeof repr.to_representation.paper_coords !== "undefined") { |
|
278 repr.redraw(); |
|
279 } |
|
280 } |
|
281 ); |
|
282 } |
|
283 |
|
284 }, |
|
285 showImage: function() { |
|
286 var _image = null; |
|
287 if (typeof this.renderer.image_cache[this.img] === "undefined") { |
|
288 _image = new Image(); |
|
289 this.renderer.image_cache[this.img] = _image; |
|
290 _image.src = this.img; |
|
291 } else { |
|
292 _image = this.renderer.image_cache[this.img]; |
|
293 } |
|
294 if (_image.width) { |
|
295 if (this.node_image) { |
|
296 this.node_image.remove(); |
|
297 } |
|
298 this.renderer.node_layer.activate(); |
|
299 var width = _image.width, |
|
300 height = _image.height, |
|
301 clipPath = this.model.get("clip_path"), |
|
302 hasClipPath = (typeof clipPath !== "undefined" && clipPath), |
|
303 _clip = null, |
|
304 baseRadius = null, |
|
305 centerPoint = null; |
|
306 |
|
307 if (hasClipPath) { |
|
308 _clip = new paper.Path(); |
|
309 var instructions = clipPath.match(/[a-z][^a-z]+/gi) || [], |
|
310 lastCoords = [0,0], |
|
311 minX = Infinity, |
|
312 minY = Infinity, |
|
313 maxX = -Infinity, |
|
314 maxY = -Infinity; |
|
315 |
|
316 var transformCoords = function(tabc, relative) { |
|
317 var newCoords = tabc.slice(1).map(function(v, k) { |
|
318 var res = parseFloat(v), |
|
319 isY = k % 2; |
|
320 if (isY) { |
|
321 res = ( res - .5 ) * height; |
|
322 } else { |
|
323 res = ( res - .5 ) * width; |
|
324 } |
|
325 if (relative) { |
|
326 res += lastCoords[isY]; |
|
327 } |
|
328 if (isY) { |
|
329 minY = Math.min(minY, res); |
|
330 maxY = Math.max(maxY, res); |
|
331 } else { |
|
332 minX = Math.min(minX, res); |
|
333 maxX = Math.max(maxX, res); |
|
334 } |
|
335 return res; |
|
336 }); |
|
337 lastCoords = newCoords.slice(-2); |
|
338 return newCoords; |
|
339 }; |
|
340 |
|
341 instructions.forEach(function(instr) { |
|
342 var coords = instr.match(/([a-z]|[0-9.-]+)/ig) || [""]; |
|
343 switch(coords[0]) { |
|
344 case "M": |
|
345 _clip.moveTo(transformCoords(coords)); |
|
346 break; |
|
347 case "m": |
|
348 _clip.moveTo(transformCoords(coords, true)); |
|
349 break; |
|
350 case "L": |
|
351 _clip.lineTo(transformCoords(coords)); |
|
352 break; |
|
353 case "l": |
|
354 _clip.lineTo(transformCoords(coords, true)); |
|
355 break; |
|
356 case "C": |
|
357 _clip.cubicCurveTo(transformCoords(coords)); |
|
358 break; |
|
359 case "c": |
|
360 _clip.cubicCurveTo(transformCoords(coords, true)); |
|
361 break; |
|
362 case "Q": |
|
363 _clip.quadraticCurveTo(transformCoords(coords)); |
|
364 break; |
|
365 case "q": |
|
366 _clip.quadraticCurveTo(transformCoords(coords, true)); |
|
367 break; |
|
368 } |
|
369 }); |
|
370 |
|
371 baseRadius = Math[this.options.node_images_fill_mode ? "min" : "max"](maxX - minX, maxY - minY) / 2; |
|
372 centerPoint = new paper.Point((maxX + minX) / 2, (maxY + minY) / 2); |
|
373 if (!this.options.show_node_circles) { |
|
374 this.h_ratio = (maxY - minY) / (2 * baseRadius); |
|
375 } |
|
376 } else { |
|
377 baseRadius = Math[this.options.node_images_fill_mode ? "min" : "max"](width, height) / 2; |
|
378 centerPoint = new paper.Point(0,0); |
|
379 if (!this.options.show_node_circles) { |
|
380 this.h_ratio = height / (2 * baseRadius); |
|
381 } |
|
382 } |
|
383 var _raster = new paper.Raster(_image); |
|
384 _raster.locked = true; // Disable mouse events on icon |
|
385 if (hasClipPath) { |
|
386 _raster = new paper.Group(_clip, _raster); |
|
387 _raster.opacity = .99; |
|
388 /* This is a workaround to allow clipping at group level |
|
389 * If opacity was set to 1, paper.js would merge all clipping groups in one (known bug). |
|
390 */ |
|
391 _raster.clipped = true; |
|
392 _clip.__representation = this; |
|
393 } |
|
394 if (this.options.clip_node_images) { |
|
395 var _circleClip = new paper.Path.Circle(centerPoint, baseRadius); |
|
396 _raster = new paper.Group(_circleClip, _raster); |
|
397 _raster.opacity = .99; |
|
398 _raster.clipped = true; |
|
399 _circleClip.__representation = this; |
|
400 } |
|
401 this.image_delta = centerPoint.divide(baseRadius); |
|
402 this.node_image = _raster; |
|
403 this.node_image.__representation = _this; |
|
404 this.node_image.scale(this.circle_radius / baseRadius); |
|
405 this.node_image.position = this.paper_coords.subtract(this.image_delta.multiply(this.circle_radius)); |
|
406 this.redraw(); |
|
407 this.renderer.throttledPaperDraw(); |
|
408 } else { |
|
409 var _this = this; |
|
410 $(_image).on("load", function() { |
|
411 _this.showImage(); |
|
412 }); |
|
413 } |
|
414 }, |
|
415 paperShift: function(_delta) { |
|
416 if (this.options.editor_mode) { |
|
417 if (!this.renkan.read_only) { |
|
418 this.is_dragging = true; |
|
419 this.paper_coords = this.paper_coords.add(_delta); |
|
420 this.redraw(); |
|
421 } |
|
422 } else { |
|
423 this.renderer.paperShift(_delta); |
|
424 } |
|
425 }, |
|
426 openEditor: function() { |
|
427 this.renderer.removeRepresentationsOfType("editor"); |
|
428 var _editor = this.renderer.addRepresentation("NodeEditor",null); |
|
429 _editor.source_representation = this; |
|
430 _editor.draw(); |
|
431 }, |
|
432 select: function() { |
|
433 this.selected = true; |
|
434 this.circle.strokeWidth = this.options.selected_node_stroke_width; |
|
435 if (this.renderer.isEditable()) { |
|
436 this.active_buttons.forEach(function(b) { |
|
437 b.show(); |
|
438 }); |
|
439 } |
|
440 var _uri = this.model.get("uri"); |
|
441 if (_uri) { |
|
442 $('.Rk-Bin-Item').each(function() { |
|
443 var _el = $(this); |
|
444 if (_el.attr("data-uri") == _uri) { |
|
445 _el.addClass("selected"); |
|
446 } |
|
447 }); |
|
448 } |
|
449 if (!this.options.editor_mode) { |
|
450 this.openEditor(); |
|
451 } |
|
452 |
|
453 if (this.renderer.minimap) { |
|
454 this.minimap_circle.strokeWidth = this.options.minimap_highlight_weight; |
|
455 this.minimap_circle.strokeColor = this.options.minimap_highlight_color; |
|
456 } |
|
457 this._super("select"); |
|
458 }, |
|
459 unselect: function(_newTarget) { |
|
460 if (!_newTarget || _newTarget.source_representation !== this) { |
|
461 this.selected = false; |
|
462 this.all_buttons.forEach(function(b) { |
|
463 b.hide(); |
|
464 }); |
|
465 this.circle.strokeWidth = this.options.node_stroke_width; |
|
466 $('.Rk-Bin-Item').removeClass("selected"); |
|
467 if (this.renderer.minimap) { |
|
468 this.minimap_circle.strokeColor = undefined; |
|
469 } |
|
470 this._super("unselect"); |
|
471 } |
|
472 }, |
|
473 highlight: function(textToReplace) { |
|
474 var hlvalue = textToReplace || true; |
|
475 if (this.highlighted === hlvalue) { |
|
476 return; |
|
477 } |
|
478 this.highlighted = hlvalue; |
|
479 this.redraw(); |
|
480 this.renderer.throttledPaperDraw(); |
|
481 }, |
|
482 unhighlight: function() { |
|
483 if (!this.highlighted) { |
|
484 return; |
|
485 } |
|
486 this.highlighted = false; |
|
487 this.redraw(); |
|
488 this.renderer.throttledPaperDraw(); |
|
489 }, |
|
490 saveCoords: function() { |
|
491 var _coords = this.renderer.toModelCoords(this.paper_coords), |
|
492 _data = { |
|
493 position: { |
|
494 x: _coords.x, |
|
495 y: _coords.y |
|
496 } |
|
497 }; |
|
498 if (this.renderer.isEditable()) { |
|
499 this.model.set(_data); |
|
500 } |
|
501 }, |
|
502 mousedown: function(_event, _isTouch) { |
|
503 if (_isTouch) { |
|
504 this.renderer.unselectAll(); |
|
505 this.select(); |
|
506 } |
|
507 }, |
|
508 mouseup: function(_event, _isTouch) { |
|
509 if (this.renderer.is_dragging && this.renderer.isEditable()) { |
|
510 this.saveCoords(); |
|
511 } else { |
|
512 if (!_isTouch && !this.model.get("delete_scheduled")) { |
|
513 this.openEditor(); |
|
514 } |
|
515 this.model.trigger("clicked"); |
|
516 } |
|
517 this.renderer.click_target = null; |
|
518 this.renderer.is_dragging = false; |
|
519 this.is_dragging = false; |
|
520 }, |
|
521 destroy: function(_event) { |
|
522 this._super("destroy"); |
|
523 this.all_buttons.forEach(function(b) { |
|
524 b.destroy(); |
|
525 }); |
|
526 this.circle.remove(); |
|
527 this.title.remove(); |
|
528 if (this.renderer.minimap) { |
|
529 this.minimap_circle.remove(); |
|
530 } |
|
531 if (this.node_image) { |
|
532 this.node_image.remove(); |
|
533 } |
|
534 } |
|
535 }); |
|
536 |
|
537 /* */ |
|
538 |
|
539 var Edge = Renderer.Edge = Rkns.Utils.inherit(_BaseRepresentation); |
|
540 |
|
541 _(Edge.prototype).extend({ |
|
542 _init: function() { |
|
543 this.renderer.edge_layer.activate(); |
|
544 this.type = "Edge"; |
|
545 this.from_representation = this.renderer.getRepresentationByModel(this.model.get("from")); |
|
546 this.to_representation = this.renderer.getRepresentationByModel(this.model.get("to")); |
|
547 this.bundle = this.renderer.addToBundles(this); |
|
548 this.line = new paper.Path(); |
|
549 this.line.add([0,0],[0,0],[0,0]); |
|
550 this.line.__representation = this; |
|
551 this.line.strokeWidth = this.options.edge_stroke_width; |
|
552 this.arrow = new paper.Path(); |
|
553 this.arrow.add( |
|
554 [ 0, 0 ], |
|
555 [ this.options.edge_arrow_length, this.options.edge_arrow_width / 2 ], |
|
556 [ 0, this.options.edge_arrow_width ] |
|
557 ); |
|
558 this.arrow.__representation = this; |
|
559 this.text = $('<div class="Rk-Label Rk-Edge-Label">').appendTo(this.renderer.labels_$); |
|
560 this.arrow_angle = 0; |
|
561 if (this.options.editor_mode) { |
|
562 this.normal_buttons = [ |
|
563 new EdgeEditButton(this.renderer, null), |
|
564 new EdgeRemoveButton(this.renderer, null) |
|
565 ]; |
|
566 this.pending_delete_buttons = [ |
|
567 new EdgeRevertButton(this.renderer, null) |
|
568 ]; |
|
569 this.all_buttons = this.normal_buttons.concat(this.pending_delete_buttons); |
|
570 for (var i = 0; i < this.all_buttons.length; i++) { |
|
571 this.all_buttons[i].source_representation = this; |
|
572 } |
|
573 this.active_buttons = []; |
|
574 } else { |
|
575 this.active_buttons = this.all_buttons = []; |
|
576 } |
|
577 |
|
578 if (this.renderer.minimap) { |
|
579 this.renderer.minimap.edge_layer.activate(); |
|
580 this.minimap_line = new paper.Path(); |
|
581 this.minimap_line.add([0,0],[0,0]); |
|
582 this.minimap_line.__representation = this.renderer.minimap.miniframe.__representation; |
|
583 this.minimap_line.strokeWidth = 1; |
|
584 } |
|
585 }, |
|
586 redraw: function() { |
|
587 var from = this.model.get("from"), |
|
588 to = this.model.get("to"); |
|
589 if (!from || !to) { |
|
590 return; |
|
591 } |
|
592 this.from_representation = this.renderer.getRepresentationByModel(from); |
|
593 this.to_representation = this.renderer.getRepresentationByModel(to); |
|
594 if (typeof this.from_representation === "undefined" || typeof this.to_representation === "undefined") { |
|
595 return; |
|
596 } |
|
597 var _p0a = this.from_representation.paper_coords, |
|
598 _p1a = this.to_representation.paper_coords, |
|
599 _v = _p1a.subtract(_p0a), |
|
600 _r = _v.length, |
|
601 _u = _v.divide(_r), |
|
602 _ortho = new paper.Point([- _u.y, _u.x]), |
|
603 _group_pos = this.bundle.getPosition(this), |
|
604 _delta = _ortho.multiply( this.options.edge_gap_in_bundles * _group_pos ), |
|
605 _p0b = _p0a.add(_delta), /* Adding a 4 px difference */ |
|
606 _p1b = _p1a.add(_delta), /* to differentiate bundled links */ |
|
607 _a = _v.angle, |
|
608 _textdelta = _ortho.multiply(this.options.edge_label_distance), |
|
609 _handle = _v.divide(3), |
|
610 _color = this.model.get("color") || this.model.get("color") || (this.model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(this.renkan)).get("color"), |
|
611 opacity = 1; |
|
612 |
|
613 if (this.model.get("delete_scheduled") || this.from_representation.model.get("delete_scheduled") || this.to_representation.model.get("delete_scheduled")) { |
|
614 opacity = .5; |
|
615 this.line.dashArray = [2, 2]; |
|
616 } else { |
|
617 opacity = 1; |
|
618 this.line.dashArray = null; |
|
619 } |
|
620 |
|
621 var old_act_btn = this.active_buttons; |
|
622 |
|
623 this.active_buttons = this.model.get("delete_scheduled") ? this.pending_delete_buttons : this.normal_buttons; |
|
624 |
|
625 if (this.selected && this.renderer.isEditable() && old_act_btn !== this.active_buttons) { |
|
626 old_act_btn.forEach(function(b) { |
|
627 b.hide(); |
|
628 }); |
|
629 this.active_buttons.forEach(function(b) { |
|
630 b.show(); |
|
631 }); |
|
632 } |
|
633 |
|
634 this.paper_coords = _p0b.add(_p1b).divide(2); |
|
635 this.line.strokeColor = _color; |
|
636 this.line.opacity = opacity; |
|
637 this.line.segments[0].point = _p0a; |
|
638 this.line.segments[1].point = this.paper_coords; |
|
639 this.line.segments[1].handleIn = _handle.multiply(-1); |
|
640 this.line.segments[1].handleOut = _handle; |
|
641 this.line.segments[2].point = _p1a; |
|
642 this.arrow.rotate(_a - this.arrow_angle); |
|
643 this.arrow.fillColor = _color; |
|
644 this.arrow.opacity = opacity; |
|
645 this.arrow.position = this.paper_coords; |
|
646 this.arrow_angle = _a; |
|
647 if (_a > 90) { |
|
648 _a -= 180; |
|
649 _textdelta = _textdelta.multiply(-1); |
|
650 } |
|
651 if (_a < -90) { |
|
652 _a += 180; |
|
653 _textdelta = _textdelta.multiply(-1); |
|
654 } |
|
655 var _text = this.model.get("title") || this.renkan.translate(this.options.label_untitled_edges) || ""; |
|
656 _text = Rkns.Utils.shortenText(_text, this.options.node_label_max_length); |
|
657 this.text.text(_text); |
|
658 var _textpos = this.paper_coords.add(_textdelta); |
|
659 this.text.css({ |
|
660 left: _textpos.x, |
|
661 top: _textpos.y, |
|
662 transform: "rotate(" + _a + "deg)", |
|
663 "-moz-transform": "rotate(" + _a + "deg)", |
|
664 "-webkit-transform": "rotate(" + _a + "deg)", |
|
665 opacity: opacity |
|
666 }); |
|
667 this.text_angle = _a; |
|
668 |
|
669 var _pc = this.paper_coords; |
|
670 this.all_buttons.forEach(function(b) { |
|
671 b.moveTo(_pc); |
|
672 }); |
|
673 |
|
674 if (this.renderer.minimap) { |
|
675 this.minimap_line.strokeColor = _color; |
|
676 this.minimap_line.segments[0].point = this.renderer.toMinimapCoords(new paper.Point(this.from_representation.model.get("position"))); |
|
677 this.minimap_line.segments[1].point = this.renderer.toMinimapCoords(new paper.Point(this.to_representation.model.get("position"))); |
|
678 } |
|
679 }, |
|
680 openEditor: function() { |
|
681 this.renderer.removeRepresentationsOfType("editor"); |
|
682 var _editor = this.renderer.addRepresentation("EdgeEditor",null); |
|
683 _editor.source_representation = this; |
|
684 _editor.draw(); |
|
685 }, |
|
686 select: function() { |
|
687 this.selected = true; |
|
688 this.line.strokeWidth = this.options.selected_edge_stroke_width; |
|
689 if (this.renderer.isEditable()) { |
|
690 this.active_buttons.forEach(function(b) { |
|
691 b.show(); |
|
692 }); |
|
693 } |
|
694 if (!this.options.editor_mode) { |
|
695 this.openEditor(); |
|
696 } |
|
697 this._super("select"); |
|
698 }, |
|
699 unselect: function(_newTarget) { |
|
700 if (!_newTarget || _newTarget.source_representation !== this) { |
|
701 this.selected = false; |
|
702 if (this.options.editor_mode) { |
|
703 this.all_buttons.forEach(function(b) { |
|
704 b.hide(); |
|
705 }); |
|
706 } |
|
707 this.line.strokeWidth = this.options.edge_stroke_width; |
|
708 this._super("unselect"); |
|
709 } |
|
710 }, |
|
711 mousedown: function(_event, _isTouch) { |
|
712 if (_isTouch) { |
|
713 this.renderer.unselectAll(); |
|
714 this.select(); |
|
715 } |
|
716 }, |
|
717 mouseup: function(_event, _isTouch) { |
|
718 if (!this.renkan.read_only && this.renderer.is_dragging) { |
|
719 this.from_representation.saveCoords(); |
|
720 this.to_representation.saveCoords(); |
|
721 this.from_representation.is_dragging = false; |
|
722 this.to_representation.is_dragging = false; |
|
723 } else { |
|
724 if (!_isTouch) { |
|
725 this.openEditor(); |
|
726 } |
|
727 this.model.trigger("clicked"); |
|
728 } |
|
729 this.renderer.click_target = null; |
|
730 this.renderer.is_dragging = false; |
|
731 }, |
|
732 paperShift: function(_delta) { |
|
733 if (this.options.editor_mode) { |
|
734 if (!this.options.read_only) { |
|
735 this.from_representation.paperShift(_delta); |
|
736 this.to_representation.paperShift(_delta); |
|
737 } |
|
738 } else { |
|
739 this.renderer.paperShift(_delta); |
|
740 } |
|
741 }, |
|
742 destroy: function() { |
|
743 this._super("destroy"); |
|
744 this.line.remove(); |
|
745 this.arrow.remove(); |
|
746 this.text.remove(); |
|
747 if (this.renderer.minimap) { |
|
748 this.minimap_line.remove(); |
|
749 } |
|
750 this.all_buttons.forEach(function(b) { |
|
751 b.destroy(); |
|
752 }); |
|
753 var _this = this; |
|
754 this.bundle.edges = _(this.bundle.edges).reject(function(_edge) { |
|
755 return _this === _edge; |
|
756 }); |
|
757 } |
|
758 }); |
|
759 |
|
760 /* */ |
|
761 |
|
762 var TempEdge = Renderer.TempEdge = Rkns.Utils.inherit(_BaseRepresentation); |
|
763 |
|
764 _(TempEdge.prototype).extend({ |
|
765 _init: function() { |
|
766 this.renderer.edge_layer.activate(); |
|
767 this.type = "Temp-edge"; |
|
768 |
|
769 var _color = (this.project.get("users").get(this.renkan.current_user) || Rkns.Utils._USER_PLACEHOLDER(this.renkan)).get("color"); |
|
770 this.line = new paper.Path(); |
|
771 this.line.strokeColor = _color; |
|
772 this.line.dashArray = [4, 2]; |
|
773 this.line.strokeWidth = this.options.selected_edge_stroke_width; |
|
774 this.line.add([0,0],[0,0]); |
|
775 this.line.__representation = this; |
|
776 this.arrow = new paper.Path(); |
|
777 this.arrow.fillColor = _color; |
|
778 this.arrow.add( |
|
779 [ 0, 0 ], |
|
780 [ this.options.edge_arrow_length, this.options.edge_arrow_width / 2 ], |
|
781 [ 0, this.options.edge_arrow_width ] |
|
782 ); |
|
783 this.arrow.__representation = this; |
|
784 this.arrow_angle = 0; |
|
785 }, |
|
786 redraw: function() { |
|
787 var _p0 = this.from_representation.paper_coords, |
|
788 _p1 = this.end_pos, |
|
789 _a = _p1.subtract(_p0).angle, |
|
790 _c = _p0.add(_p1).divide(2); |
|
791 this.line.segments[0].point = _p0; |
|
792 this.line.segments[1].point = _p1; |
|
793 this.arrow.rotate(_a - this.arrow_angle); |
|
794 this.arrow.position = _c; |
|
795 this.arrow_angle = _a; |
|
796 }, |
|
797 paperShift: function(_delta) { |
|
798 if (!this.renderer.isEditable()) { |
|
799 this.renderer.removeRepresentation(_this); |
|
800 paper.view.draw(); |
|
801 return; |
|
802 } |
|
803 this.end_pos = this.end_pos.add(_delta); |
|
804 var _hitResult = paper.project.hitTest(this.end_pos); |
|
805 this.renderer.findTarget(_hitResult); |
|
806 this.redraw(); |
|
807 }, |
|
808 mouseup: function(_event, _isTouch) { |
|
809 var _hitResult = paper.project.hitTest(_event.point), |
|
810 _model = this.from_representation.model, |
|
811 _endDrag = true; |
|
812 if (_hitResult && typeof _hitResult.item.__representation !== "undefined") { |
|
813 var _target = _hitResult.item.__representation; |
|
814 if (_target.type.substr(0,4) === "Node") { |
|
815 var _destmodel = _target.model || _target.source_representation.model; |
|
816 if (_model !== _destmodel) { |
|
817 var _data = { |
|
818 id: Rkns.Utils.getUID('edge'), |
|
819 created_by: this.renkan.current_user, |
|
820 from: _model, |
|
821 to: _destmodel |
|
822 }; |
|
823 if (this.renderer.isEditable()) { |
|
824 this.project.addEdge(_data); |
|
825 } |
|
826 } |
|
827 } |
|
828 |
|
829 if (_model === _target.model || (_target.source_representation && _target.source_representation.model === _model)) { |
|
830 _endDrag = false; |
|
831 this.renderer.is_dragging = true; |
|
832 } |
|
833 } |
|
834 if (_endDrag) { |
|
835 this.renderer.click_target = null; |
|
836 this.renderer.is_dragging = false; |
|
837 this.renderer.removeRepresentation(this); |
|
838 paper.view.draw(); |
|
839 } |
|
840 }, |
|
841 destroy: function() { |
|
842 this.arrow.remove(); |
|
843 this.line.remove(); |
|
844 } |
|
845 }); |
|
846 |
|
847 /* */ |
|
848 |
|
849 var _BaseEditor = Renderer._BaseEditor = Rkns.Utils.inherit(_BaseRepresentation); |
|
850 |
|
851 _(_BaseEditor.prototype).extend({ |
|
852 _init: function() { |
|
853 this.renderer.buttons_layer.activate(); |
|
854 this.type = "editor"; |
|
855 this.editor_block = new paper.Path(); |
|
856 var _pts = _(_.range(8)).map(function() {return [0,0];}); |
|
857 this.editor_block.add.apply(this.editor_block, _pts); |
|
858 this.editor_block.strokeWidth = this.options.tooltip_border_width; |
|
859 this.editor_block.strokeColor = this.options.tooltip_border_color; |
|
860 this.editor_block.opacity = .8; |
|
861 this.editor_$ = $('<div>') |
|
862 .appendTo(this.renderer.editor_$) |
|
863 .css({ |
|
864 position: "absolute", |
|
865 opacity: .8 |
|
866 }) |
|
867 .hide(); |
|
868 }, |
|
869 destroy: function() { |
|
870 this.editor_block.remove(); |
|
871 this.editor_$.remove(); |
|
872 } |
|
873 }); |
|
874 |
|
875 /* */ |
|
876 |
|
877 var NodeEditor = Renderer.NodeEditor = Rkns.Utils.inherit(_BaseEditor); |
|
878 |
|
879 _(NodeEditor.prototype).extend({ |
|
880 template: _.template( |
|
881 '<h2><span class="Rk-CloseX">×</span><%-renkan.translate("Edit Node")%></span></h2>' |
|
882 + '<p><label><%-renkan.translate("Title:")%></label><input class="Rk-Edit-Title" type="text" value="<%-node.title%>"/></p>' |
|
883 + '<% if (options.show_node_editor_uri) { %><p><label><%-renkan.translate("URI:")%></label><input class="Rk-Edit-URI" type="text" value="<%-node.uri%>"/><a class="Rk-Edit-Goto" href="<%-node.uri%>" target="_blank"></a></p><% } %>' |
|
884 + '<% if (options.show_node_editor_description) { %><p><label><%-renkan.translate("Description:")%></label><textarea class="Rk-Edit-Description"><%-node.description%></textarea></p><% } %>' |
|
885 + '<% if (options.show_node_editor_size) { %><p><span class="Rk-Editor-Label"><%-renkan.translate("Size:")%></span><a href="#" class="Rk-Edit-Size-Down">-</a><span class="Rk-Edit-Size-Value"><%-node.size%></span><a href="#" class="Rk-Edit-Size-Up">+</a></p><% } %>' |
|
886 + '<% if (options.show_node_editor_color) { %><div class="Rk-Editor-p"><span class="Rk-Editor-Label"><%-renkan.translate("Node color:")%></span><div class="Rk-Edit-ColorPicker-Wrapper"><span class="Rk-Edit-Color" style="background:<%-node.color%>;"><span class="Rk-Edit-ColorTip"></span></span>' |
|
887 + '<%= renkan.colorPicker %><span class="Rk-Edit-ColorPicker-Text"><%- renkan.translate("Choose color") %></span></div></div><% } %>' |
|
888 + '<% if (options.show_node_editor_image) { %><div class="Rk-Edit-ImgWrap"><div class="Rk-Edit-ImgPreview"><img src="<%-node.image || node.image_placeholder%>" />' |
|
889 + '<% if (node.clip_path) { %><svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 1 1" preserveAspectRatio="none"><path style="stroke-width: .02; stroke:red; fill-opacity:.3; fill:red;" d="<%- node.clip_path %>"/></svg><% }%>' |
|
890 + '</div></div><p><label><%-renkan.translate("Image URL:")%></label><input class="Rk-Edit-Image" type="text" value="<%-node.image%>"/></p>' |
|
891 + '<p><label><%-renkan.translate("Choose Image File:")%></label><input class="Rk-Edit-Image-File" type="file" accept="image/*"/></p><% } %>' |
|
892 + '<% if (options.show_node_editor_creator && node.has_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><% } %>' |
|
893 ), |
|
894 readOnlyTemplate: _.template( |
|
895 '<h2><span class="Rk-CloseX">×</span><% if (options.show_node_tooltip_color) { %><span class="Rk-UserColor" style="background:<%-node.color%>;"></span><% } %>' |
|
896 + '<span class="Rk-Display-Title"><% if (node.uri) { %><a href="<%-node.uri%>" target="_blank"><% } %><%-node.title%><% if (node.uri) { %></a><% } %></span></h2>' |
|
897 + '<% if (node.uri && options.show_node_tooltip_uri) { %><p class="Rk-Display-URI"><a href="<%-node.uri%>" target="_blank"><%-node.short_uri%></a></p><% } %>' |
|
898 + '<% if (options.show_node_tooltip_description) { %><p class="Rk-Display-Description"><%-node.description%></p><% } %>' |
|
899 + '<% if (node.image && options.show_node_tooltip_image) { %><img class="Rk-Display-ImgPreview" src="<%-node.image%>" /><% } %>' |
|
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><% } %>' |
|
901 ), |
|
902 draw: function() { |
|
903 var _model = this.source_representation.model, |
|
904 _created_by = _model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(this.renkan), |
|
905 _template = (this.renderer.isEditable() ? this.template : this.readOnlyTemplate ), |
|
906 _image_placeholder = this.options.static_url + "img/image-placeholder.png", |
|
907 _size = (_model.get("size") || 0); |
|
908 this.editor_$ |
|
909 .html(_template({ |
|
910 node: { |
|
911 has_creator: !!_model.get("created_by"), |
|
912 title: _model.get("title"), |
|
913 uri: _model.get("uri"), |
|
914 short_uri: Rkns.Utils.shortenText((_model.get("uri") || "").replace(/^(https?:\/\/)?(www\.)?/,'').replace(/\/$/,''),40), |
|
915 description: _model.get("description"), |
|
916 image: _model.get("image") || "", |
|
917 image_placeholder: _image_placeholder, |
|
918 color: _model.get("color") || _created_by.get("color"), |
|
919 clip_path: _model.get("clip_path") || false, |
|
920 created_by_color: _created_by.get("color"), |
|
921 created_by_title: _created_by.get("title"), |
|
922 size: (_size > 0 ? "+" : "") + _size |
|
923 }, |
|
924 renkan: this.renkan, |
|
925 options: this.options, |
|
926 shortenText: Rkns.Utils.shortenText |
|
927 })); |
|
928 this.redraw(); |
|
929 var _this = this, |
|
930 closeEditor = function() { |
|
931 _this.renderer.removeRepresentation(_this); |
|
932 paper.view.draw(); |
|
933 }; |
|
934 |
|
935 this.editor_$.find(".Rk-CloseX").click(closeEditor); |
|
936 |
|
937 this.editor_$.find(".Rk-Edit-Goto").click(function() { |
|
938 if (!_model.get("uri")) { |
|
939 return false; |
|
940 } |
|
941 }); |
|
942 |
|
943 if (this.renderer.isEditable()) { |
|
944 |
|
945 var onFieldChange = _(function() { |
|
946 _(function() { |
|
947 if (_this.renderer.isEditable()) { |
|
948 var _data = { |
|
949 title: _this.editor_$.find(".Rk-Edit-Title").val() |
|
950 }; |
|
951 if (_this.options.show_node_editor_uri) { |
|
952 _data.uri = _this.editor_$.find(".Rk-Edit-URI").val(); |
|
953 _this.editor_$.find(".Rk-Edit-Goto").attr("href",_data.uri || "#"); |
|
954 } |
|
955 if (_this.options.show_node_editor_image) { |
|
956 _data.image = _this.editor_$.find(".Rk-Edit-Image").val(); |
|
957 _this.editor_$.find(".Rk-Edit-ImgPreview").attr("src", _data.image || _image_placeholder); |
|
958 } |
|
959 if (_this.options.show_node_editor_description) { |
|
960 _data.description = _this.editor_$.find(".Rk-Edit-Description").val(); |
|
961 } |
|
962 _model.set(_data); |
|
963 _this.redraw(); |
|
964 } else { |
|
965 closeEditor(); |
|
966 } |
|
967 |
|
968 }).defer(); |
|
969 }).throttle(500); |
|
970 |
|
971 this.editor_$.on("keyup", function(_e) { |
|
972 if (_e.keyCode === 27) { |
|
973 closeEditor(); |
|
974 } |
|
975 }); |
|
976 |
|
977 this.editor_$.find("input, textarea").on("change keyup paste", onFieldChange); |
|
978 |
|
979 this.editor_$.find(".Rk-Edit-Image-File").change(function() { |
|
980 if (this.files.length) { |
|
981 var f = this.files[0], |
|
982 fr = new FileReader(); |
|
983 if (f.type.substr(0,5) !== "image") { |
|
984 alert(_this.renkan.translate("This file is not an image")); |
|
985 return; |
|
986 } |
|
987 if (f.size > (_this.options.uploaded_image_max_kb * 1024)) { |
|
988 alert(_this.renkan.translate("Image size must be under ") + _this.options.uploaded_image_max_kb + _this.renkan.translate("KB")); |
|
989 return; |
|
990 } |
|
991 fr.onload = function(e) { |
|
992 _this.editor_$.find(".Rk-Edit-Image").val(e.target.result); |
|
993 onFieldChange(); |
|
994 }; |
|
995 fr.readAsDataURL(f); |
|
996 } |
|
997 }); |
|
998 this.editor_$.find(".Rk-Edit-Title")[0].focus(); |
|
999 |
|
1000 var _picker = _this.editor_$.find(".Rk-Edit-ColorPicker"); |
|
1001 |
|
1002 this.editor_$.find(".Rk-Edit-ColorPicker-Wrapper").hover( |
|
1003 function(_e) { |
|
1004 _e.preventDefault(); |
|
1005 _picker.show(); |
|
1006 }, |
|
1007 function(_e) { |
|
1008 _e.preventDefault(); |
|
1009 _picker.hide(); |
|
1010 } |
|
1011 ); |
|
1012 |
|
1013 _picker.find("li").hover( |
|
1014 function(_e) { |
|
1015 _e.preventDefault(); |
|
1016 _this.editor_$.find(".Rk-Edit-Color").css("background", $(this).attr("data-color")); |
|
1017 }, |
|
1018 function(_e) { |
|
1019 _e.preventDefault(); |
|
1020 _this.editor_$.find(".Rk-Edit-Color").css("background", _model.get("color") || (_model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(_this.renkan)).get("color")); |
|
1021 } |
|
1022 ).click(function(_e) { |
|
1023 _e.preventDefault(); |
|
1024 if (_this.renderer.isEditable()) { |
|
1025 _model.set("color", $(this).attr("data-color")); |
|
1026 _picker.hide(); |
|
1027 paper.view.draw(); |
|
1028 } else { |
|
1029 closeEditor(); |
|
1030 } |
|
1031 }); |
|
1032 |
|
1033 var shiftSize = function(n) { |
|
1034 if (_this.renderer.isEditable()) { |
|
1035 var _newsize = n+(_model.get("size") || 0); |
|
1036 _this.editor_$.find(".Rk-Edit-Size-Value").text((_newsize > 0 ? "+" : "") + _newsize); |
|
1037 _model.set("size", _newsize); |
|
1038 paper.view.draw(); |
|
1039 } else { |
|
1040 closeEditor(); |
|
1041 } |
|
1042 }; |
|
1043 |
|
1044 this.editor_$.find(".Rk-Edit-Size-Down").click(function() { |
|
1045 shiftSize(-1); |
|
1046 return false; |
|
1047 }); |
|
1048 this.editor_$.find(".Rk-Edit-Size-Up").click(function() { |
|
1049 shiftSize(1); |
|
1050 return false; |
|
1051 }); |
|
1052 } else { |
|
1053 if (typeof this.source_representation.highlighted === "object") { |
|
1054 var titlehtml = this.source_representation.highlighted.replace(_(_model.get("title")).escape(),'<span class="Rk-Highlighted">$1</span>'); |
|
1055 this.editor_$.find(".Rk-Display-Title" + (_model.get("uri") ? " a" : "")).html(titlehtml); |
|
1056 if (this.options.show_node_tooltip_description) { |
|
1057 this.editor_$.find(".Rk-Display-Description").html(this.source_representation.highlighted.replace(_(_model.get("description")).escape(),'<span class="Rk-Highlighted">$1</span>')); |
|
1058 } |
|
1059 } |
|
1060 } |
|
1061 this.editor_$.find("img").load(function() { |
|
1062 _this.redraw(); |
|
1063 }); |
|
1064 }, |
|
1065 redraw: function() { |
|
1066 var _coords = this.source_representation.paper_coords; |
|
1067 Rkns.Utils.drawEditBox(this.options, _coords, this.editor_block, this.source_representation.circle_radius * .75, this.editor_$); |
|
1068 this.editor_$.show(); |
|
1069 paper.view.draw(); |
|
1070 } |
|
1071 }); |
|
1072 |
|
1073 /* */ |
|
1074 |
|
1075 var EdgeEditor = Renderer.EdgeEditor = Rkns.Utils.inherit(_BaseEditor); |
|
1076 |
|
1077 _(EdgeEditor.prototype).extend({ |
|
1078 template: _.template( |
|
1079 '<h2><span class="Rk-CloseX">×</span><%-renkan.translate("Edit Edge")%></span></h2>' |
|
1080 + '<p><label><%-renkan.translate("Title:")%></label><input class="Rk-Edit-Title" type="text" value="<%-edge.title%>"/></p>' |
|
1081 + '<% if (options.show_edge_editor_uri) { %><p><label><%-renkan.translate("URI:")%></label><input class="Rk-Edit-URI" type="text" value="<%-edge.uri%>"/><a class="Rk-Edit-Goto" href="<%-edge.uri%>" target="_blank"></a></p>' |
|
1082 + '<% if (options.properties.length) { %><p><label><%-renkan.translate("Choose from vocabulary:")%></label><select class="Rk-Edit-Vocabulary">' |
|
1083 + '<% _(options.properties).each(function(ontology) { %><option class="Rk-Edit-Vocabulary-Class" value=""><%- renkan.translate(ontology.label) %></option>' |
|
1084 + '<% _(ontology.properties).each(function(property) { var uri = ontology["base-uri"] + property.uri; %><option class="Rk-Edit-Vocabulary-Property" value="<%- uri %>' |
|
1085 + '"<% if (uri === edge.uri) { %> selected<% } %>><%- renkan.translate(property.label) %></option>' |
|
1086 + '<% }) %><% }) %></select></p><% } } %>' |
|
1087 + '<% if (options.show_edge_editor_color) { %><div class="Rk-Editor-p"><span class="Rk-Editor-Label"><%-renkan.translate("Edge color:")%></span><div class="Rk-Edit-ColorPicker-Wrapper"><span class="Rk-Edit-Color" style="background:<%-edge.color%>;"><span class="Rk-Edit-ColorTip"></span></span>' |
|
1088 + '<%= renkan.colorPicker %><span class="Rk-Edit-ColorPicker-Text"><%- renkan.translate("Choose color") %></span></div></div><% } %>' |
|
1089 + '<% if (options.show_edge_editor_direction) { %><p><span class="Rk-Edit-Direction"><%- renkan.translate("Change edge direction") %></span></p><% } %>' |
|
1090 + '<% if (options.show_edge_editor_nodes) { %><p><span class="Rk-Editor-Label"><%-renkan.translate("From:")%></span><span class="Rk-UserColor" style="background:<%-edge.from_color%>;"></span><%- shortenText(edge.from_title, 25) %></p>' |
|
1091 + '<p><span class="Rk-Editor-Label"><%-renkan.translate("To:")%></span><span class="Rk-UserColor" style="background:<%-edge.to_color%>;"></span><%- shortenText(edge.to_title, 25) %></p><% } %>' |
|
1092 + '<% if (options.show_edge_editor_creator && edge.has_creator) { %><p><span class="Rk-Editor-Label"><%-renkan.translate("Created by:")%></span><span class="Rk-UserColor" style="background:<%-edge.created_by_color%>;"></span><%- shortenText(edge.created_by_title, 25) %></p><% } %>' |
|
1093 ), |
|
1094 readOnlyTemplate: _.template( |
|
1095 '<h2><span class="Rk-CloseX">×</span><% if (options.show_edge_tooltip_color) { %><span class="Rk-UserColor" style="background:<%-edge.color%>;"></span><% } %>' |
|
1096 + '<span class="Rk-Display-Title"><% if (edge.uri) { %><a href="<%-edge.uri%>" target="_blank"><% } %><%-edge.title%><% if (edge.uri) { %></a><% } %></span></h2>' |
|
1097 + '<% if (options.show_edge_tooltip_uri && edge.uri) { %><p class="Rk-Display-URI"><a href="<%-edge.uri%>" target="_blank"><%-edge.short_uri%></a></p><% } %>' |
|
1098 + '<p><%-edge.description%></p>' |
|
1099 + '<% if (options.show_edge_tooltip_nodes) { %><p><span class="Rk-Editor-Label"><%-renkan.translate("From:")%></span><span class="Rk-UserColor" style="background:<%-edge.from_color%>;"></span><%- shortenText(edge.from_title, 25) %></p>' |
|
1100 + '<p><span class="Rk-Editor-Label"><%-renkan.translate("To:")%></span><span class="Rk-UserColor" style="background:<%-edge.to_color%>;"></span><%- shortenText(edge.to_title, 25) %></p><% } %>' |
|
1101 + '<% if (options.show_edge_tooltip_creator && edge.has_creator) { %><p><span class="Rk-Editor-Label"><%-renkan.translate("Created by:")%></span><span class="Rk-UserColor" style="background:<%-edge.created_by_color%>;"></span><%- shortenText(edge.created_by_title, 25) %></p><% } %>' |
|
1102 ), |
|
1103 draw: function() { |
|
1104 var _model = this.source_representation.model, |
|
1105 _from_model = _model.get("from"), |
|
1106 _to_model = _model.get("to"), |
|
1107 _created_by = _model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(this.renkan), |
|
1108 _template = (this.renderer.isEditable() ? this.template : this.readOnlyTemplate); |
|
1109 this.editor_$ |
|
1110 .html(_template({ |
|
1111 edge: { |
|
1112 has_creator: !!_model.get("created_by"), |
|
1113 title: _model.get("title"), |
|
1114 uri: _model.get("uri"), |
|
1115 short_uri: Rkns.Utils.shortenText((_model.get("uri") || "").replace(/^(https?:\/\/)?(www\.)?/,'').replace(/\/$/,''),40), |
|
1116 description: _model.get("description"), |
|
1117 color: _model.get("color") || _created_by.get("color"), |
|
1118 from_title: _from_model.get("title"), |
|
1119 to_title: _to_model.get("title"), |
|
1120 from_color: _from_model.get("color") || (_from_model.get("created_by") || Rkns.Utils._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"), |
|
1122 created_by_color: _created_by.get("color"), |
|
1123 created_by_title: _created_by.get("title") |
|
1124 }, |
|
1125 renkan: this.renkan, |
|
1126 shortenText: Rkns.Utils.shortenText, |
|
1127 options: this.options |
|
1128 })); |
|
1129 this.redraw(); |
|
1130 var _this = this, |
|
1131 closeEditor = function() { |
|
1132 _this.renderer.removeRepresentation(_this); |
|
1133 paper.view.draw(); |
|
1134 }; |
|
1135 this.editor_$.find(".Rk-CloseX").click(closeEditor); |
|
1136 this.editor_$.find(".Rk-Edit-Goto").click(function() { |
|
1137 if (!_model.get("uri")) { |
|
1138 return false; |
|
1139 } |
|
1140 }); |
|
1141 |
|
1142 if (this.renderer.isEditable()) { |
|
1143 |
|
1144 var onFieldChange = _(function() { |
|
1145 _(function() { |
|
1146 if (_this.renderer.isEditable()) { |
|
1147 var _data = { |
|
1148 title: _this.editor_$.find(".Rk-Edit-Title").val() |
|
1149 }; |
|
1150 if (_this.options.show_edge_editor_uri) { |
|
1151 _data.uri = _this.editor_$.find(".Rk-Edit-URI").val(); |
|
1152 } |
|
1153 _this.editor_$.find(".Rk-Edit-Goto").attr("href",_data.uri || "#"); |
|
1154 _model.set(_data); |
|
1155 paper.view.draw(); |
|
1156 } else { |
|
1157 closeEditor(); |
|
1158 } |
|
1159 }).defer(); |
|
1160 }).throttle(500); |
|
1161 |
|
1162 this.editor_$.on("keyup", function(_e) { |
|
1163 if (_e.keyCode === 27) { |
|
1164 closeEditor(); |
|
1165 } |
|
1166 }); |
|
1167 |
|
1168 this.editor_$.find("input").on("keyup change paste", onFieldChange); |
|
1169 |
|
1170 this.editor_$.find(".Rk-Edit-Vocabulary").change(function() { |
|
1171 var e = $(this), |
|
1172 v = e.val(); |
|
1173 if (v) { |
|
1174 _this.editor_$.find(".Rk-Edit-Title").val(e.find(":selected").text()); |
|
1175 _this.editor_$.find(".Rk-Edit-URI").val(v); |
|
1176 onFieldChange(); |
|
1177 } |
|
1178 }); |
|
1179 this.editor_$.find(".Rk-Edit-Direction").click(function() { |
|
1180 if (_this.renderer.isEditable()) { |
|
1181 _model.set({ |
|
1182 from: _model.get("to"), |
|
1183 to: _model.get("from") |
|
1184 }); |
|
1185 _this.draw(); |
|
1186 } else { |
|
1187 closeEditor(); |
|
1188 } |
|
1189 }); |
|
1190 |
|
1191 var _picker = _this.editor_$.find(".Rk-Edit-ColorPicker"); |
|
1192 |
|
1193 this.editor_$.find(".Rk-Edit-ColorPicker-Wrapper").hover( |
|
1194 function(_e) { |
|
1195 _e.preventDefault(); |
|
1196 _picker.show(); |
|
1197 }, |
|
1198 function(_e) { |
|
1199 _e.preventDefault(); |
|
1200 _picker.hide(); |
|
1201 } |
|
1202 ); |
|
1203 |
|
1204 _picker.find("li").hover( |
|
1205 function(_e) { |
|
1206 _e.preventDefault(); |
|
1207 _this.editor_$.find(".Rk-Edit-Color").css("background", $(this).attr("data-color")); |
|
1208 }, |
|
1209 function(_e) { |
|
1210 _e.preventDefault(); |
|
1211 _this.editor_$.find(".Rk-Edit-Color").css("background", _model.get("color") || (_model.get("created_by") || Rkns.Utils._USER_PLACEHOLDER(_this.renkan)).get("color")); |
|
1212 } |
|
1213 ).click(function(_e) { |
|
1214 _e.preventDefault(); |
|
1215 if (_this.renderer.isEditable()) { |
|
1216 _model.set("color", $(this).attr("data-color")); |
|
1217 _picker.hide(); |
|
1218 paper.view.draw(); |
|
1219 } else { |
|
1220 closeEditor(); |
|
1221 } |
|
1222 }); |
|
1223 } |
|
1224 }, |
|
1225 redraw: function() { |
|
1226 var _coords = this.source_representation.paper_coords; |
|
1227 Rkns.Utils.drawEditBox(this.options, _coords, this.editor_block, 5, this.editor_$); |
|
1228 this.editor_$.show(); |
|
1229 paper.view.draw(); |
|
1230 } |
|
1231 }); |
|
1232 |
|
1233 /* */ |
|
1234 |
|
1235 var _NodeButton = Renderer._NodeButton = Rkns.Utils.inherit(_BaseButton); |
|
1236 |
|
1237 _(_NodeButton.prototype).extend({ |
|
1238 setSectorSize: function() { |
|
1239 var sectorInner = this.source_representation.circle_radius; |
|
1240 if (sectorInner !== this.lastSectorInner) { |
|
1241 if (this.sector) { |
|
1242 this.sector.destroy(); |
|
1243 } |
|
1244 this.sector = this.renderer.drawSector( |
|
1245 this, 1 + sectorInner, |
|
1246 Rkns.Utils._NODE_BUTTON_WIDTH + sectorInner, |
|
1247 this.startAngle, |
|
1248 this.endAngle, |
|
1249 1, |
|
1250 this.imageName, |
|
1251 this.renkan.translate(this.text) |
|
1252 ); |
|
1253 this.lastSectorInner = sectorInner; |
|
1254 } |
|
1255 } |
|
1256 }); |
|
1257 |
|
1258 /* */ |
|
1259 |
|
1260 var NodeEditButton = Renderer.NodeEditButton = Rkns.Utils.inherit(_NodeButton); |
|
1261 |
|
1262 _(NodeEditButton.prototype).extend({ |
|
1263 _init: function() { |
|
1264 this.type = "Node-edit-button"; |
|
1265 this.lastSectorInner = 0; |
|
1266 this.startAngle = -135; |
|
1267 this.endAngle = -45; |
|
1268 this.imageName = "edit"; |
|
1269 this.text = "Edit"; |
|
1270 }, |
|
1271 mouseup: function() { |
|
1272 if (!this.renderer.is_dragging) { |
|
1273 this.source_representation.openEditor(); |
|
1274 } |
|
1275 } |
|
1276 }); |
|
1277 |
|
1278 /* */ |
|
1279 |
|
1280 var NodeRemoveButton = Renderer.NodeRemoveButton = Rkns.Utils.inherit(_NodeButton); |
|
1281 |
|
1282 _(NodeRemoveButton.prototype).extend({ |
|
1283 _init: function() { |
|
1284 this.type = "Node-remove-button"; |
|
1285 this.lastSectorInner = 0; |
|
1286 this.startAngle = 0; |
|
1287 this.endAngle = 90; |
|
1288 this.imageName = "remove"; |
|
1289 this.text = "Remove"; |
|
1290 }, |
|
1291 mouseup: function() { |
|
1292 this.renderer.click_target = null; |
|
1293 this.renderer.is_dragging = false; |
|
1294 this.renderer.removeRepresentationsOfType("editor"); |
|
1295 if (this.renderer.isEditable()) { |
|
1296 if (this.options.element_delete_delay) { |
|
1297 var delid = Rkns.Utils.getUID("delete"); |
|
1298 this.renderer.delete_list.push({ |
|
1299 id: delid, |
|
1300 time: new Date().valueOf() + this.options.element_delete_delay |
|
1301 }); |
|
1302 this.source_representation.model.set("delete_scheduled", delid); |
|
1303 } else { |
|
1304 if (confirm(this.renkan.translate('Do you really wish to remove node ') + '"' + this.source_representation.model.get("title") + '"?')) { |
|
1305 this.project.removeNode(this.source_representation.model); |
|
1306 } |
|
1307 } |
|
1308 } |
|
1309 } |
|
1310 }); |
|
1311 |
|
1312 /* */ |
|
1313 |
|
1314 var NodeRevertButton = Renderer.NodeRevertButton = Rkns.Utils.inherit(_NodeButton); |
|
1315 |
|
1316 _(NodeRevertButton.prototype).extend({ |
|
1317 _init: function() { |
|
1318 this.type = "Node-revert-button"; |
|
1319 this.lastSectorInner = 0; |
|
1320 this.startAngle = -135; |
|
1321 this.endAngle = 135; |
|
1322 this.imageName = "revert"; |
|
1323 this.text = "Cancel deletion"; |
|
1324 }, |
|
1325 mouseup: function() { |
|
1326 this.renderer.click_target = null; |
|
1327 this.renderer.is_dragging = false; |
|
1328 if (this.renderer.isEditable()) { |
|
1329 this.source_representation.model.unset("delete_scheduled"); |
|
1330 } |
|
1331 } |
|
1332 }); |
|
1333 |
|
1334 /* */ |
|
1335 |
|
1336 var NodeLinkButton = Renderer.NodeLinkButton = Rkns.Utils.inherit(_NodeButton); |
|
1337 |
|
1338 _(NodeLinkButton.prototype).extend({ |
|
1339 _init: function() { |
|
1340 this.type = "Node-link-button"; |
|
1341 this.lastSectorInner = 0; |
|
1342 this.startAngle = 90; |
|
1343 this.endAngle = 180; |
|
1344 this.imageName = "link"; |
|
1345 this.text = "Link to another node"; |
|
1346 }, |
|
1347 mousedown: function(_event, _isTouch) { |
|
1348 if (this.renderer.isEditable()) { |
|
1349 var _off = this.renderer.canvas_$.offset(), |
|
1350 _point = new paper.Point([ |
|
1351 _event.pageX - _off.left, |
|
1352 _event.pageY - _off.top |
|
1353 ]); |
|
1354 this.renderer.click_target = null; |
|
1355 this.renderer.removeRepresentationsOfType("editor"); |
|
1356 this.renderer.addTempEdge(this.source_representation, _point); |
|
1357 } |
|
1358 } |
|
1359 }); |
|
1360 |
|
1361 /* */ |
|
1362 |
|
1363 var NodeEnlargeButton = Renderer.NodeEnlargeButton = Rkns.Utils.inherit(_NodeButton); |
|
1364 |
|
1365 _(NodeEnlargeButton.prototype).extend({ |
|
1366 _init: function() { |
|
1367 this.type = "Node-enlarge-button"; |
|
1368 this.lastSectorInner = 0; |
|
1369 this.startAngle = -45; |
|
1370 this.endAngle = 0; |
|
1371 this.imageName = "enlarge"; |
|
1372 this.text = "Enlarge"; |
|
1373 }, |
|
1374 mouseup: function() { |
|
1375 var _newsize = 1 + (this.source_representation.model.get("size") || 0); |
|
1376 this.source_representation.model.set("size", _newsize); |
|
1377 this.source_representation.select(); |
|
1378 this.select(); |
|
1379 paper.view.draw(); |
|
1380 } |
|
1381 }); |
|
1382 |
|
1383 /* */ |
|
1384 |
|
1385 var NodeShrinkButton = Renderer.NodeShrinkButton = Rkns.Utils.inherit(_NodeButton); |
|
1386 |
|
1387 _(NodeShrinkButton.prototype).extend({ |
|
1388 _init: function() { |
|
1389 this.type = "Node-shrink-button"; |
|
1390 this.lastSectorInner = 0; |
|
1391 this.startAngle = -180; |
|
1392 this.endAngle = -135; |
|
1393 this.imageName = "shrink"; |
|
1394 this.text = "Shrink"; |
|
1395 }, |
|
1396 mouseup: function() { |
|
1397 var _newsize = -1 + (this.source_representation.model.get("size") || 0); |
|
1398 this.source_representation.model.set("size", _newsize); |
|
1399 this.source_representation.select(); |
|
1400 this.select(); |
|
1401 paper.view.draw(); |
|
1402 } |
|
1403 }); |
|
1404 |
|
1405 /* */ |
|
1406 |
|
1407 var EdgeEditButton = Renderer.EdgeEditButton = Rkns.Utils.inherit(_BaseButton); |
|
1408 |
|
1409 _(EdgeEditButton.prototype).extend({ |
|
1410 _init: function() { |
|
1411 this.type = "Edge-edit-button"; |
|
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")); |
|
1413 }, |
|
1414 mouseup: function() { |
|
1415 if (!this.renderer.is_dragging) { |
|
1416 this.source_representation.openEditor(); |
|
1417 } |
|
1418 } |
|
1419 }); |
|
1420 |
|
1421 /* */ |
|
1422 |
|
1423 var EdgeRemoveButton = Renderer.EdgeRemoveButton = Rkns.Utils.inherit(_BaseButton); |
|
1424 |
|
1425 _(EdgeRemoveButton.prototype).extend({ |
|
1426 _init: function() { |
|
1427 this.type = "Edge-remove-button"; |
|
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")); |
|
1429 }, |
|
1430 mouseup: function() { |
|
1431 this.renderer.click_target = null; |
|
1432 this.renderer.is_dragging = false; |
|
1433 this.renderer.removeRepresentationsOfType("editor"); |
|
1434 if (this.renderer.isEditable()) { |
|
1435 if (this.options.element_delete_delay) { |
|
1436 var delid = Rkns.Utils.getUID("delete"); |
|
1437 this.renderer.delete_list.push({ |
|
1438 id: delid, |
|
1439 time: new Date().valueOf() + this.options.element_delete_delay |
|
1440 }); |
|
1441 this.source_representation.model.set("delete_scheduled", delid); |
|
1442 } else { |
|
1443 if (confirm(this.renkan.translate('Do you really wish to remove edge ') + '"' + this.source_representation.model.get("title") + '"?')) { |
|
1444 this.project.removeEdge(this.source_representation.model); |
|
1445 } |
|
1446 } |
|
1447 } |
|
1448 } |
|
1449 }); |
|
1450 |
|
1451 /* */ |
|
1452 |
|
1453 var EdgeRevertButton = Renderer.EdgeRevertButton = Rkns.Utils.inherit(_BaseButton); |
|
1454 |
|
1455 _(EdgeRevertButton.prototype).extend({ |
|
1456 _init: function() { |
|
1457 this.type = "Edge-revert-button"; |
|
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")); |
|
1459 }, |
|
1460 mouseup: function() { |
|
1461 this.renderer.click_target = null; |
|
1462 this.renderer.is_dragging = false; |
|
1463 if (this.renderer.isEditable()) { |
|
1464 this.source_representation.model.unset("delete_scheduled"); |
|
1465 } |
|
1466 } |
|
1467 }); |
|
1468 |
|
1469 /* */ |
|
1470 |
|
1471 var MiniFrame = Renderer.MiniFrame = Rkns.Utils.inherit(_BaseRepresentation); |
|
1472 |
|
1473 _(MiniFrame.prototype).extend({ |
|
1474 paperShift: function(_delta) { |
|
1475 this.renderer.offset = this.renderer.offset.subtract(_delta.divide(this.renderer.minimap.scale).multiply(this.renderer.scale)); |
|
1476 this.renderer.redraw(); |
|
1477 }, |
|
1478 mouseup: function(_delta) { |
|
1479 this.renderer.click_target = null; |
|
1480 this.renderer.is_dragging = false; |
|
1481 } |
|
1482 }); |
|
1483 |
|
1484 /* */ |
|
1485 |
|
1486 var Scene = Renderer.Scene = function(_renkan) { |
|
1487 this.renkan = _renkan; |
|
1488 this.$ = $(".Rk-Render"); |
|
1489 this.representations = []; |
|
1490 this.$.html(this.template(_renkan)); |
|
1491 this.onStatusChange(); |
|
1492 this.canvas_$ = this.$.find(".Rk-Canvas"); |
|
1493 this.labels_$ = this.$.find(".Rk-Labels"); |
|
1494 this.editor_$ = this.$.find(".Rk-Editor"); |
|
1495 this.notif_$ = this.$.find(".Rk-Notifications"); |
|
1496 paper.setup(this.canvas_$[0]); |
|
1497 this.scale = 1; |
|
1498 this.initialScale = 1; |
|
1499 this.offset = paper.view.center; |
|
1500 this.totalScroll = 0; |
|
1501 this.mouse_down = false; |
|
1502 this.click_target = null; |
|
1503 this.selected_target = null; |
|
1504 this.edge_layer = new paper.Layer(); |
|
1505 this.node_layer = new paper.Layer(); |
|
1506 this.buttons_layer = new paper.Layer(); |
|
1507 this.delete_list = []; |
|
1508 |
|
1509 if (_renkan.options.show_minimap) { |
|
1510 this.minimap = { |
|
1511 background_layer: new paper.Layer(), |
|
1512 edge_layer: new paper.Layer(), |
|
1513 node_layer: new paper.Layer(), |
|
1514 node_group: new paper.Group(), |
|
1515 size: new paper.Size( _renkan.options.minimap_width, _renkan.options.minimap_height ) |
|
1516 }; |
|
1517 |
|
1518 this.minimap.background_layer.activate(); |
|
1519 this.minimap.topleft = paper.view.bounds.bottomRight.subtract(this.minimap.size); |
|
1520 this.minimap.rectangle = new paper.Path.Rectangle(this.minimap.topleft.subtract([2,2]), this.minimap.size.add([4,4])); |
|
1521 this.minimap.rectangle.fillColor = _renkan.options.minimap_background_color; |
|
1522 this.minimap.rectangle.strokeColor = _renkan.options.minimap_border_color; |
|
1523 this.minimap.rectangle.strokeWidth = 4; |
|
1524 this.minimap.offset = new paper.Point(this.minimap.size.divide(2)); |
|
1525 this.minimap.scale = .1; |
|
1526 |
|
1527 this.minimap.node_layer.activate(); |
|
1528 this.minimap.cliprectangle = new paper.Path.Rectangle(this.minimap.topleft, this.minimap.size); |
|
1529 this.minimap.node_group.addChild(this.minimap.cliprectangle); |
|
1530 this.minimap.node_group.clipped = true; |
|
1531 this.minimap.miniframe = new paper.Path.Rectangle(this.minimap.topleft, this.minimap.size); |
|
1532 this.minimap.node_group.addChild(this.minimap.miniframe); |
|
1533 this.minimap.miniframe.fillColor = '#c0c0ff'; |
|
1534 this.minimap.miniframe.opacity = .3; |
|
1535 this.minimap.miniframe.strokeColor = '#000080'; |
|
1536 this.minimap.miniframe.strokeWidth = 3; |
|
1537 this.minimap.miniframe.__representation = new MiniFrame(this, null); |
|
1538 } |
|
1539 |
|
1540 this.throttledPaperDraw = _(function() { |
|
1541 paper.view.draw(); |
|
1542 }).throttle(100); |
|
1543 |
|
1544 this.bundles = []; |
|
1545 this.click_mode = false; |
|
1546 |
|
1547 var _this = this, |
|
1548 _allowScroll = true, |
|
1549 _originalScale = 1, |
|
1550 _zooming = false, |
|
1551 _lastTapX = 0, |
|
1552 _lastTapY = 0; |
|
1553 |
|
1554 this.image_cache = {}; |
|
1555 this.icon_cache = {}; |
|
1556 |
|
1557 ['edit', 'remove', 'link', 'enlarge', 'shrink', 'revert' ].forEach(function(imgname) { |
|
1558 var img = new Image(); |
|
1559 img.src = _renkan.options.static_url + 'img/' + imgname + '.png'; |
|
1560 _this.icon_cache[imgname] = img; |
|
1561 }); |
|
1562 |
|
1563 var throttledMouseMove = _.throttle(function(_event, _isTouch) { |
|
1564 _this.onMouseMove(_event, _isTouch); |
|
1565 }, Rkns.Utils._MOUSEMOVE_RATE); |
|
1566 |
|
1567 this.canvas_$.on({ |
|
1568 mousedown: function(_event) { |
|
1569 _event.preventDefault(); |
|
1570 _this.onMouseDown(_event, false); |
|
1571 }, |
|
1572 mousemove: function(_event) { |
|
1573 _event.preventDefault(); |
|
1574 throttledMouseMove(_event, false); |
|
1575 }, |
|
1576 mouseup: function(_event) { |
|
1577 _event.preventDefault(); |
|
1578 _this.onMouseUp(_event, false); |
|
1579 }, |
|
1580 mousewheel: function(_event, _delta) { |
|
1581 if(_renkan.options.zoom_on_scroll) { |
|
1582 _event.preventDefault(); |
|
1583 if (_allowScroll) { |
|
1584 _this.onScroll(_event, _delta); |
|
1585 } |
|
1586 } |
|
1587 }, |
|
1588 touchstart: function(_event) { |
|
1589 _event.preventDefault(); |
|
1590 var _touches = _event.originalEvent.touches[0]; |
|
1591 if ( |
|
1592 _renkan.options.allow_double_click |
|
1593 && new Date() - _lastTap < Rkns.Utils._DOUBLETAP_DELAY |
|
1594 && ( Math.pow(_lastTapX - _touches.pageX, 2) + Math.pow(_lastTapY - _touches.pageY, 2) < Rkns.Utils._DOUBLETAP_DISTANCE ) |
|
1595 ) { |
|
1596 _lastTap = 0; |
|
1597 _this.onDoubleClick(_touches); |
|
1598 } else { |
|
1599 _lastTap = new Date(); |
|
1600 _lastTapX = _touches.pageX; |
|
1601 _lastTapY = _touches.pageY; |
|
1602 _originalScale = _this.scale; |
|
1603 _zooming = false; |
|
1604 _this.onMouseDown(_touches, true); |
|
1605 } |
|
1606 }, |
|
1607 touchmove: function(_event) { |
|
1608 _event.preventDefault(); |
|
1609 _lastTap = 0; |
|
1610 if (_event.originalEvent.touches.length == 1) { |
|
1611 _this.onMouseMove(_event.originalEvent.touches[0], true); |
|
1612 } else { |
|
1613 if (!_zooming) { |
|
1614 _this.onMouseUp(_event.originalEvent.touches[0], true); |
|
1615 _this.click_target = null; |
|
1616 _this.is_dragging = false; |
|
1617 _zooming = true; |
|
1618 } |
|
1619 if (_event.originalEvent.scale === "undefined") { |
|
1620 return; |
|
1621 } |
|
1622 var _newScale = _event.originalEvent.scale * _originalScale, |
|
1623 _scaleRatio = _newScale / _this.scale, |
|
1624 _newOffset = new paper.Point([ |
|
1625 _this.canvas_$.width(), |
|
1626 _this.canvas_$.height() |
|
1627 ]).multiply( .5 * ( 1 - _scaleRatio ) ).add(_this.offset.multiply( _scaleRatio )); |
|
1628 _this.setScale(_newScale, _newOffset); |
|
1629 } |
|
1630 }, |
|
1631 touchend: function(_event) { |
|
1632 _event.preventDefault(); |
|
1633 _this.onMouseUp(_event.originalEvent.changedTouches[0], true); |
|
1634 }, |
|
1635 dblclick: function(_event) { |
|
1636 _event.preventDefault(); |
|
1637 if (_renkan.options.allow_double_click) { |
|
1638 _this.onDoubleClick(_event); |
|
1639 } |
|
1640 }, |
|
1641 mouseleave: function(_event) { |
|
1642 _event.preventDefault(); |
|
1643 _this.onMouseUp(_event, false); |
|
1644 _this.click_target = null; |
|
1645 _this.is_dragging = false; |
|
1646 }, |
|
1647 dragover: function(_event) { |
|
1648 _event.preventDefault(); |
|
1649 }, |
|
1650 dragenter: function(_event) { |
|
1651 _event.preventDefault(); |
|
1652 _allowScroll = false; |
|
1653 }, |
|
1654 dragleave: function(_event) { |
|
1655 _event.preventDefault(); |
|
1656 _allowScroll = true; |
|
1657 }, |
|
1658 drop: function(_event) { |
|
1659 _event.preventDefault(); |
|
1660 _allowScroll = true; |
|
1661 var res = {}; |
|
1662 _(_event.originalEvent.dataTransfer.types).each(function(t) { |
|
1663 try { |
|
1664 res[t] = _event.originalEvent.dataTransfer.getData(t); |
|
1665 } catch(e) {} |
|
1666 }); |
|
1667 var text = _event.originalEvent.dataTransfer.getData("Text"); |
|
1668 if (typeof text === "string") { |
|
1669 switch(text[0]) { |
|
1670 case "{": |
|
1671 case "[": |
|
1672 try { |
|
1673 var data = JSON.parse(text); |
|
1674 _(res).extend(data); |
|
1675 } |
|
1676 catch(e) { |
|
1677 if (!res["text/plain"]) { |
|
1678 res["text/plain"] = text; |
|
1679 } |
|
1680 } |
|
1681 break; |
|
1682 case "<": |
|
1683 if (!res["text/html"]) { |
|
1684 res["text/html"] = text; |
|
1685 } |
|
1686 break; |
|
1687 default: |
|
1688 if (!res["text/plain"]) { |
|
1689 res["text/plain"] = text; |
|
1690 } |
|
1691 } |
|
1692 } |
|
1693 var url = _event.originalEvent.dataTransfer.getData("URL"); |
|
1694 if (url && !res["text/uri-list"]) { |
|
1695 res["text/uri-list"] = url; |
|
1696 } |
|
1697 _this.dropData(res, _event.originalEvent); |
|
1698 } |
|
1699 }); |
|
1700 |
|
1701 var bindClick = function(selector, fname) { |
|
1702 _this.$.find(selector).click(function(evt) { |
|
1703 _this[fname](evt); |
|
1704 return false; |
|
1705 }); |
|
1706 }; |
|
1707 |
|
1708 bindClick(".Rk-ZoomOut", "zoomOut"); |
|
1709 bindClick(".Rk-ZoomIn", "zoomIn"); |
|
1710 bindClick(".Rk-ZoomFit", "autoScale"); |
|
1711 this.$.find(".Rk-ZoomSave").click( function() { |
|
1712 // Save scale and offset point |
|
1713 _this.renkan.project.addView( { zoom_level:_this.scale, offset_x:_this.offset.x, offset_y:_this.offset.y } ); |
|
1714 }); |
|
1715 this.$.find(".Rk-ZoomSetSaved").click( function() { |
|
1716 var view = _this.renkan.project.get("views").last(); |
|
1717 if(view){ |
|
1718 _this.setScale(view.get("zoom_level"), new paper.Point(view.get("offset_x"), view.get("offset_y"))); |
|
1719 } |
|
1720 }); |
|
1721 if(this.renkan.read_only && !isNaN(parseInt(this.renkan.options.default_view))){ |
|
1722 this.$.find(".Rk-ZoomSetSaved").show(); |
|
1723 } |
|
1724 this.$.find(".Rk-CurrentUser").mouseenter( |
|
1725 function() { _this.$.find(".Rk-UserList").slideDown(); } |
|
1726 ); |
|
1727 this.$.find(".Rk-Users").mouseleave( |
|
1728 function() { _this.$.find(".Rk-UserList").slideUp(); } |
|
1729 ); |
|
1730 bindClick(".Rk-FullScreen-Button", "fullScreen"); |
|
1731 bindClick(".Rk-AddNode-Button", "addNodeBtn"); |
|
1732 bindClick(".Rk-AddEdge-Button", "addEdgeBtn"); |
|
1733 bindClick(".Rk-Save-Button", "save"); |
|
1734 bindClick(".Rk-Open-Button", "open"); |
|
1735 this.$.find(".Rk-Bookmarklet-Button") |
|
1736 .attr("href","javascript:" + Rkns.Utils._BOOKMARKLET_CODE(_renkan)) |
|
1737 .click(function(){ |
|
1738 _this.notif_$ |
|
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.")) |
|
1740 .fadeIn() |
|
1741 .delay(5000) |
|
1742 .fadeOut(); |
|
1743 return false; |
|
1744 }); |
|
1745 this.$.find(".Rk-TopBar-Button").mouseover(function() { |
|
1746 $(this).find(".Rk-TopBar-Tooltip").show(); |
|
1747 }).mouseout(function() { |
|
1748 $(this).find(".Rk-TopBar-Tooltip").hide(); |
|
1749 }); |
|
1750 bindClick(".Rk-Fold-Bins", "foldBins"); |
|
1751 |
|
1752 paper.view.onResize = function(_event) { |
|
1753 // Because of paper bug which does not calculate the good height (and width a fortiori) |
|
1754 // We have to update manually the canvas's height |
|
1755 paper.view._viewSize.height = _event.size.height = _this.canvas_$.parent().height(); |
|
1756 |
|
1757 if (_this.minimap) { |
|
1758 _this.minimap.topleft = paper.view.bounds.bottomRight.subtract(_this.minimap.size); |
|
1759 _this.minimap.rectangle.fitBounds(_this.minimap.topleft.subtract([2,2]), _this.minimap.size.add([4,4])); |
|
1760 _this.minimap.cliprectangle.fitBounds(_this.minimap.topleft, _this.minimap.size); |
|
1761 } |
|
1762 _this.redraw(); |
|
1763 }; |
|
1764 |
|
1765 var _thRedraw = _.throttle(function() { |
|
1766 _this.redraw(); |
|
1767 },50); |
|
1768 |
|
1769 this.addRepresentations("Node", this.renkan.project.get("nodes")); |
|
1770 this.addRepresentations("Edge", this.renkan.project.get("edges")); |
|
1771 this.renkan.project.on("change:title", function() { |
|
1772 _this.$.find(".Rk-PadTitle").val(_renkan.project.get("title")); |
|
1773 }); |
|
1774 |
|
1775 this.$.find(".Rk-PadTitle").on("keyup input paste", function() { |
|
1776 _renkan.project.set({"title": $(this).val()}); |
|
1777 }); |
|
1778 |
|
1779 var _thRedrawUsers = _.throttle(function() { |
|
1780 _this.redrawUsers(); |
|
1781 }, 100); |
|
1782 |
|
1783 _thRedrawUsers(); |
|
1784 |
|
1785 // register model events |
|
1786 this.renkan.project.on("add:users remove:users", _thRedrawUsers); |
|
1787 |
|
1788 this.renkan.project.on("add:views remove:views", function(_node) { |
|
1789 if(_this.renkan.project.get('views').length > 0) { |
|
1790 _this.$.find(".Rk-ZoomSetSaved").show(); |
|
1791 } |
|
1792 else { |
|
1793 _this.$.find(".Rk-ZoomSetSaved").hide(); |
|
1794 } |
|
1795 }); |
|
1796 |
|
1797 this.renkan.project.on("add:nodes", function(_node) { |
|
1798 _this.addRepresentation("Node", _node); |
|
1799 _thRedraw(); |
|
1800 }); |
|
1801 this.renkan.project.on("add:edges", function(_edge) { |
|
1802 _this.addRepresentation("Edge", _edge); |
|
1803 _thRedraw(); |
|
1804 }); |
|
1805 this.renkan.project.on("change:title", function(_model, _title) { |
|
1806 var el = _this.$.find(".Rk-PadTitle"); |
|
1807 if (el.is("input")) { |
|
1808 if (el.val() !== _title) { |
|
1809 el.val(_title); |
|
1810 } |
|
1811 } else { |
|
1812 el.text(_title); |
|
1813 } |
|
1814 }); |
|
1815 |
|
1816 if (_renkan.options.size_bug_fix) { |
|
1817 var _delay = ( |
|
1818 typeof _renkan.options.size_bug_fix === "number" |
|
1819 ? _renkan.options.size_bug_fix |
|
1820 : 500 |
|
1821 ); |
|
1822 window.setTimeout( |
|
1823 function() { |
|
1824 _this.fixSize(true); |
|
1825 }, |
|
1826 _delay |
|
1827 ); |
|
1828 } |
|
1829 |
|
1830 if (_renkan.options.force_resize) { |
|
1831 $(window).resize(function() { |
|
1832 _this.fixSize(false); |
|
1833 }); |
|
1834 } |
|
1835 |
|
1836 if (_renkan.options.show_user_list && _renkan.options.user_color_editable) { |
|
1837 var $cpwrapper = this.$.find(".Rk-Users .Rk-Edit-ColorPicker-Wrapper"), |
|
1838 $cplist = this.$.find(".Rk-Users .Rk-Edit-ColorPicker"); |
|
1839 |
|
1840 $cpwrapper.hover( |
|
1841 function(_e) { |
|
1842 if (_this.isEditable()) { |
|
1843 _e.preventDefault(); |
|
1844 $cplist.show(); |
|
1845 } |
|
1846 }, |
|
1847 function(_e) { |
|
1848 _e.preventDefault(); |
|
1849 $cplist.hide(); |
|
1850 } |
|
1851 ); |
|
1852 |
|
1853 $cplist.find("li").mouseenter( |
|
1854 function(_e) { |
|
1855 if (_this.isEditable()) { |
|
1856 _e.preventDefault(); |
|
1857 _this.$.find(".Rk-CurrentUser-Color").css("background", $(this).attr("data-color")); |
|
1858 } |
|
1859 } |
|
1860 ); |
|
1861 } |
|
1862 |
|
1863 if (_renkan.options.show_search_field) { |
|
1864 |
|
1865 var lastval = ''; |
|
1866 |
|
1867 this.$.find(".Rk-GraphSearch-Field").on("keyup change paste input", function() { |
|
1868 var $this = $(this), |
|
1869 val = $this.val(); |
|
1870 if (val === lastval) { |
|
1871 return; |
|
1872 } |
|
1873 lastval = val; |
|
1874 if (val.length < 2) { |
|
1875 _renkan.project.get("nodes").each(function(n) { |
|
1876 _this.getRepresentationByModel(n).unhighlight(); |
|
1877 }); |
|
1878 } else { |
|
1879 var rxs = Rkns.Utils.regexpFromTextOrArray(val); |
|
1880 _renkan.project.get("nodes").each(function(n) { |
|
1881 if (rxs.test(n.get("title")) || rxs.test(n.get("description"))) { |
|
1882 _this.getRepresentationByModel(n).highlight(rxs); |
|
1883 } else { |
|
1884 _this.getRepresentationByModel(n).unhighlight(); |
|
1885 } |
|
1886 }); |
|
1887 } |
|
1888 }); |
|
1889 } |
|
1890 |
|
1891 this.redraw(); |
|
1892 |
|
1893 window.setInterval(function() { |
|
1894 var _now = new Date().valueOf(); |
|
1895 _this.delete_list.forEach(function(d) { |
|
1896 if (_now >= d.time) { |
|
1897 var el = _renkan.project.get("nodes").findWhere({"delete_scheduled":d.id}); |
|
1898 if (el) { |
|
1899 project.removeNode(el); |
|
1900 } |
|
1901 el = _renkan.project.get("edges").findWhere({"delete_scheduled":d.id}); |
|
1902 if (el) { |
|
1903 project.removeEdge(el); |
|
1904 } |
|
1905 } |
|
1906 }); |
|
1907 _this.delete_list = _this.delete_list.filter(function(d) { |
|
1908 return _renkan.project.get("nodes").findWhere({"delete_scheduled":d.id}) || _renkan.project.get("edges").findWhere({"delete_scheduled":d.id}); |
|
1909 }); |
|
1910 }, 500); |
|
1911 |
|
1912 if (this.minimap) { |
|
1913 window.setInterval(function() { |
|
1914 _this.rescaleMinimap(); |
|
1915 }, 2000); |
|
1916 } |
|
1917 |
|
1918 }; |
|
1919 |
|
1920 _(Scene.prototype).extend({ |
|
1921 template: _.template( |
|
1922 '<% if (options.show_top_bar) { %><div class="Rk-TopBar"><% if (!options.editor_mode) { %><h2 class="Rk-PadTitle"><%- project.get("title") || translate("Untitled project")%></h2>' |
|
1923 + '<% } else { %><input type="text" class="Rk-PadTitle" value="<%- project.get("title") || "" %>" placeholder="<%-translate("Untitled project")%>" /><% } %>' |
|
1924 + '<% if (options.show_user_list) { %><div class="Rk-Users"><div class="Rk-CurrentUser"><div class="Rk-Edit-ColorPicker-Wrapper"><span class="Rk-CurrentUser-Color"><% if (options.user_color_editable) { %><span class="Rk-Edit-ColorTip"></span><% } %></span>' |
|
1925 + '<% if (options.user_color_editable) { print(colorPicker) } %></div><span class="Rk-CurrentUser-Name"><unknown user></span></div><ul class="Rk-UserList"></ul></div><% } %>' |
|
1926 + '<% if (options.home_button_url) {%><div class="Rk-TopBar-Separator"></div><a class="Rk-TopBar-Button Rk-Home-Button" href="<%- options.home_button_url %>"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Contents">' |
|
1927 + '<%- translate(options.home_button_title) %></div></div></a><% } %>' |
|
1928 + '<% if (options.show_fullscreen_button) { %><div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-FullScreen-Button"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Contents"><%-translate("Full Screen")%></div></div></div><% } %>' |
|
1929 + '<% if (options.editor_mode) { %>' |
|
1930 + '<% if (options.show_addnode_button) { %><div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-AddNode-Button"><div class="Rk-TopBar-Tooltip">' |
|
1931 + '<div class="Rk-TopBar-Tooltip-Contents"><%-translate("Add Node")%></div></div></div><% } %>' |
|
1932 + '<% if (options.show_addedge_button) { %><div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-AddEdge-Button"><div class="Rk-TopBar-Tooltip">' |
|
1933 + '<div class="Rk-TopBar-Tooltip-Contents"><%-translate("Add Edge")%></div></div></div><% } %>' |
|
1934 + '<% if (options.show_save_button) { %><div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-Save-Button"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Contents"> </div></div></div><% } %>' |
|
1935 + '<% if (options.show_open_button) { %><div class="Rk-TopBar-Separator"></div><div class="Rk-TopBar-Button Rk-Open-Button"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Contents"><%-translate("Open Project")%></div></div></div><% } %>' |
|
1936 + '<% if (options.show_bookmarklet) { %><div class="Rk-TopBar-Separator"></div><a class="Rk-TopBar-Button Rk-Bookmarklet-Button" href="#"><div class="Rk-TopBar-Tooltip"><div class="Rk-TopBar-Tooltip-Contents">' |
|
1937 + '<%-translate("Renkan \'Drag-to-Add\' bookmarklet")%></div></div></a><% } %>' |
|
1938 + '<div class="Rk-TopBar-Separator"></div><% }; if (options.show_search_field) { %>' |
|
1939 + '<form action="#" class="Rk-GraphSearch-Form"><input type="search" class="Rk-GraphSearch-Field" placeholder="<%- translate("Search in graph") %>" /></form><div class="Rk-TopBar-Separator"></div><% } %></div><% } %>' |
|
1940 + '<div class="Rk-Editing-Space<% if (!options.show_top_bar) { %> Rk-Editing-Space-Full<% } %>">' |
|
1941 + '<div class="Rk-Labels"></div><canvas class="Rk-Canvas" resize></canvas><div class="Rk-Notifications"></div><div class="Rk-Editor">' |
|
1942 + '<% if (options.show_bins) { %><div class="Rk-Fold-Bins">«</div><% } %>' |
|
1943 + '<div class="Rk-ZoomButtons"><div class="Rk-ZoomIn" title="<%-translate("Zoom In")%>"></div><div class="Rk-ZoomFit" title="<%-translate("Zoom Fit")%>"></div><div class="Rk-ZoomOut" title="<%-translate("Zoom Out")%>"></div>' |
|
1944 + '<% if (options.editor_mode) { %><div class="Rk-ZoomSave" title="<%-translate("Zoom Save")%>"></div><% } %>' |
|
1945 + '<% if (options.editor_mode || !isNaN(parseInt(options.default_view))) { %><div class="Rk-ZoomSetSaved" title="<%-translate("View saved zoom")%>"></div><% } %></div>' |
|
1946 + '</div></div>' |
|
1947 ), |
|
1948 fixSize: function(_autoscale) { |
|
1949 var w = this.$.width(), |
|
1950 h = this.$.height(); |
|
1951 if (this.renkan.options.show_top_bar) { |
|
1952 h -= this.$.find(".Rk-TopBar").height(); |
|
1953 } |
|
1954 this.canvas_$.attr({ |
|
1955 width: w, |
|
1956 height: h |
|
1957 }); |
|
1958 |
|
1959 paper.view.viewSize = new paper.Size([w, h]); |
|
1960 |
|
1961 if (_autoscale) { |
|
1962 // If _autoscale, we get the initial view (zoom+offset) set in the project datas. |
|
1963 if(this.renkan.read_only && !isNaN(parseInt(this.renkan.options.default_view))){ |
|
1964 this.autoScale(this.renkan.project.get("views")[parseInt(this.renkan.options.default_view)]); |
|
1965 } |
|
1966 else{ |
|
1967 this.autoScale(); |
|
1968 } |
|
1969 } |
|
1970 }, |
|
1971 drawSector: function(_repr, _inR, _outR, _startAngle, _endAngle, _padding, _imgname, _caption) { |
|
1972 var _options = this.renkan.options, |
|
1973 _startRads = _startAngle * Math.PI / 180, |
|
1974 _endRads = _endAngle * Math.PI / 180, |
|
1975 _img = this.icon_cache[_imgname], |
|
1976 _startdx = - Math.sin(_startRads), |
|
1977 _startdy = Math.cos(_startRads), |
|
1978 _startXIn = Math.cos(_startRads) * _inR + _padding * _startdx, |
|
1979 _startYIn = Math.sin(_startRads) * _inR + _padding * _startdy, |
|
1980 _startXOut = Math.cos(_startRads) * _outR + _padding * _startdx, |
|
1981 _startYOut = Math.sin(_startRads) * _outR + _padding * _startdy, |
|
1982 _enddx = - Math.sin(_endRads), |
|
1983 _enddy = Math.cos(_endRads), |
|
1984 _endXIn = Math.cos(_endRads) * _inR - _padding * _enddx, |
|
1985 _endYIn = Math.sin(_endRads) * _inR - _padding * _enddy, |
|
1986 _endXOut = Math.cos(_endRads) * _outR - _padding * _enddx, |
|
1987 _endYOut = Math.sin(_endRads) * _outR - _padding * _enddy, |
|
1988 _centerR = (_inR + _outR)/2, |
|
1989 _centerRads = (_startRads + _endRads) / 2, |
|
1990 _centerX = Math.cos(_centerRads) * _centerR, |
|
1991 _centerY = Math.sin(_centerRads) * _centerR, |
|
1992 _centerXIn = Math.cos(_centerRads) * _inR, |
|
1993 _centerXOut = Math.cos(_centerRads) * _outR, |
|
1994 _centerYIn = Math.sin(_centerRads) * _inR, |
|
1995 _centerYOut = Math.sin(_centerRads) * _outR, |
|
1996 _textX = Math.cos(_centerRads) * (_outR + 3), |
|
1997 _textY = Math.sin(_centerRads) * (_outR + _options.buttons_label_font_size) + _options.buttons_label_font_size / 2; |
|
1998 this.buttons_layer.activate(); |
|
1999 var _path = new paper.Path(); |
|
2000 _path.add([_startXIn, _startYIn]); |
|
2001 _path.arcTo([_centerXIn, _centerYIn], [_endXIn, _endYIn]); |
|
2002 _path.lineTo([_endXOut, _endYOut]); |
|
2003 _path.arcTo([_centerXOut, _centerYOut], [_startXOut, _startYOut]); |
|
2004 _path.fillColor = _options.buttons_background; |
|
2005 _path.opacity = .5; |
|
2006 _path.closed = true; |
|
2007 _path.__representation = _repr; |
|
2008 var _text = new paper.PointText(_textX,_textY); |
|
2009 _text.characterStyle = { |
|
2010 fontSize: _options.buttons_label_font_size, |
|
2011 fillColor: _options.buttons_label_color |
|
2012 }; |
|
2013 if (_textX > 2) { |
|
2014 _text.paragraphStyle.justification = 'left'; |
|
2015 } else if (_textX < -2) { |
|
2016 _text.paragraphStyle.justification = 'right'; |
|
2017 } else { |
|
2018 _text.paragraphStyle.justification = 'center'; |
|
2019 } |
|
2020 _text.visible = false; |
|
2021 var _visible = false, |
|
2022 _restPos = new paper.Point(-200, -200), |
|
2023 _grp = new paper.Group([_path, _text]), |
|
2024 _delta = _grp.position, |
|
2025 _imgdelta = new paper.Point([_centerX, _centerY]), |
|
2026 _currentPos = new paper.Point(0,0); |
|
2027 _text.content = _caption; |
|
2028 _grp.visible = false; |
|
2029 _grp.position = _restPos; |
|
2030 var _res = { |
|
2031 show: function() { |
|
2032 _visible = true; |
|
2033 _grp.position = _currentPos.add(_delta); |
|
2034 _grp.visible = true; |
|
2035 }, |
|
2036 moveTo: function(_point) { |
|
2037 _currentPos = _point; |
|
2038 if (_visible) { |
|
2039 _grp.position = _point.add(_delta); |
|
2040 } |
|
2041 }, |
|
2042 hide: function() { |
|
2043 _visible = false; |
|
2044 _grp.visible = false; |
|
2045 _grp.position = _restPos; |
|
2046 }, |
|
2047 select: function() { |
|
2048 _path.opacity = .8; |
|
2049 _text.visible = true; |
|
2050 }, |
|
2051 unselect: function() { |
|
2052 _path.opacity = .5; |
|
2053 _text.visible = false; |
|
2054 }, |
|
2055 destroy: function() { |
|
2056 _grp.remove(); |
|
2057 } |
|
2058 }; |
|
2059 var showImage = function() { |
|
2060 var _raster = new paper.Raster(_img); |
|
2061 _raster.position = _imgdelta.add(_grp.position).subtract(_delta); |
|
2062 _raster.locked = true; // Disable mouse events on icon |
|
2063 _grp.addChild(_raster); |
|
2064 }; |
|
2065 if (_img.width) { |
|
2066 showImage(); |
|
2067 } else { |
|
2068 $(_img).on("load",showImage); |
|
2069 } |
|
2070 |
|
2071 return _res; |
|
2072 }, |
|
2073 addToBundles: function(_edgeRepr) { |
|
2074 var _bundle = _(this.bundles).find(function(_bundle) { |
|
2075 return ( |
|
2076 ( _bundle.from === _edgeRepr.from_representation && _bundle.to === _edgeRepr.to_representation ) |
|
2077 || ( _bundle.from === _edgeRepr.to_representation && _bundle.to === _edgeRepr.from_representation ) |
|
2078 ); |
|
2079 }); |
|
2080 if (typeof _bundle !== "undefined") { |
|
2081 _bundle.edges.push(_edgeRepr); |
|
2082 } else { |
|
2083 _bundle = { |
|
2084 from: _edgeRepr.from_representation, |
|
2085 to: _edgeRepr.to_representation, |
|
2086 edges: [ _edgeRepr ], |
|
2087 getPosition: function(_er) { |
|
2088 var _dir = (_er.from_representation === this.from) ? 1 : -1; |
|
2089 return _dir * ( _(this.edges).indexOf(_er) - (this.edges.length - 1) / 2 ); |
|
2090 } |
|
2091 }; |
|
2092 this.bundles.push(_bundle); |
|
2093 } |
|
2094 return _bundle; |
|
2095 }, |
|
2096 isEditable: function() { |
|
2097 return (this.renkan.options.editor_mode && !this.renkan.read_only); |
|
2098 }, |
|
2099 onStatusChange: function() { |
|
2100 var savebtn = this.$.find(".Rk-Save-Button"), |
|
2101 tip = savebtn.find(".Rk-TopBar-Tooltip-Contents"); |
|
2102 if (this.renkan.read_only) { |
|
2103 savebtn.removeClass("disabled Rk-Save-Online").addClass("Rk-Save-ReadOnly"); |
|
2104 tip.text(this.renkan.translate("Connection lost")); |
|
2105 } else { |
|
2106 if (this.renkan.options.snapshot_mode) { |
|
2107 savebtn.removeClass("Rk-Save-ReadOnly Rk-Save-Online"); |
|
2108 tip.text(this.renkan.translate("Save Project")); |
|
2109 } else { |
|
2110 savebtn.removeClass("disabled Rk-Save-ReadOnly").addClass("Rk-Save-Online"); |
|
2111 tip.text(this.renkan.translate("Auto-save enabled")); |
|
2112 } |
|
2113 } |
|
2114 this.redrawUsers(); |
|
2115 }, |
|
2116 setScale: function(_newScale, _offset) { |
|
2117 if ((_newScale/this.initialScale) > Rkns.Utils._MIN_SCALE && (_newScale/this.initialScale) < Rkns.Utils._MAX_SCALE) { |
|
2118 this.scale = _newScale; |
|
2119 if (_offset) { |
|
2120 this.offset = _offset; |
|
2121 } |
|
2122 this.redraw(); |
|
2123 } |
|
2124 }, |
|
2125 autoScale: function(force_view) { |
|
2126 var nodes = this.renkan.project.get("nodes"); |
|
2127 if (nodes.length > 1) { |
|
2128 var _xx = nodes.map(function(_node) { return _node.get("position").x; }), |
|
2129 _yy = nodes.map(function(_node) { return _node.get("position").y; }), |
|
2130 _minx = Math.min.apply(Math, _xx), |
|
2131 _miny = Math.min.apply(Math, _yy), |
|
2132 _maxx = Math.max.apply(Math, _xx), |
|
2133 _maxy = Math.max.apply(Math, _yy); |
|
2134 var _scale = Math.min( (paper.view.size.width - 2 * this.renkan.options.autoscale_padding) / (_maxx - _minx), (paper.view.size.height - 2 * this.renkan.options.autoscale_padding) / (_maxy - _miny)); |
|
2135 this.initialScale = _scale; |
|
2136 // Override calculated scale if asked |
|
2137 if((typeof force_view !== "undefined") && parseFloat(force_view.zoom_level)>0 && parseFloat(force_view.offset_x)>0 && parseFloat(force_view.offset_y)>0){ |
|
2138 this.setScale(parseFloat(force_view.zoom_level), new paper.Point(parseFloat(force_view.offset_x), parseFloat(force_view.offset_y))); |
|
2139 } |
|
2140 else{ |
|
2141 this.setScale(_scale, paper.view.center.subtract(new paper.Point([(_maxx + _minx) / 2, (_maxy + _miny) / 2]).multiply(_scale))); |
|
2142 } |
|
2143 } |
|
2144 if (nodes.length === 1) { |
|
2145 this.setScale(1, paper.view.center.subtract(new paper.Point([nodes.at(0).get("position").x, nodes.at(0).get("position").y]))); |
|
2146 } |
|
2147 }, |
|
2148 redrawMiniframe: function() { |
|
2149 var topleft = this.toMinimapCoords(this.toModelCoords(new paper.Point([0,0]))), |
|
2150 bottomright = this.toMinimapCoords(this.toModelCoords(paper.view.bounds.bottomRight)); |
|
2151 this.minimap.miniframe.fitBounds(topleft, bottomright); |
|
2152 }, |
|
2153 rescaleMinimap: function() { |
|
2154 var nodes = this.renkan.project.get("nodes"); |
|
2155 if (nodes.length > 1) { |
|
2156 var _xx = nodes.map(function(_node) { return _node.get("position").x; }), |
|
2157 _yy = nodes.map(function(_node) { return _node.get("position").y; }), |
|
2158 _minx = Math.min.apply(Math, _xx), |
|
2159 _miny = Math.min.apply(Math, _yy), |
|
2160 _maxx = Math.max.apply(Math, _xx), |
|
2161 _maxy = Math.max.apply(Math, _yy); |
|
2162 var _scale = Math.min( |
|
2163 this.scale * .8 * this.renkan.options.minimap_width / paper.view.bounds.width, |
|
2164 this.scale * .8 * this.renkan.options.minimap_height / paper.view.bounds.height, |
|
2165 ( this.renkan.options.minimap_width - 2 * this.renkan.options.minimap_padding ) / (_maxx - _minx), |
|
2166 ( this.renkan.options.minimap_height - 2 * this.renkan.options.minimap_padding ) / (_maxy - _miny) |
|
2167 ); |
|
2168 this.minimap.offset = this.minimap.size.divide(2).subtract(new paper.Point([(_maxx + _minx) / 2, (_maxy + _miny) / 2]).multiply(_scale)); |
|
2169 this.minimap.scale = _scale; |
|
2170 } |
|
2171 if (nodes.length === 1) { |
|
2172 this.minimap.scale = .1; |
|
2173 this.minimap.offset = this.minimap.size.divide(2).subtract(new paper.Point([nodes.at(0).get("position").x, nodes.at(0).get("position").y]).multiply(this.minimap.scale)); |
|
2174 } |
|
2175 this.redraw(); |
|
2176 }, |
|
2177 toPaperCoords: function(_point) { |
|
2178 return _point.multiply(this.scale).add(this.offset); |
|
2179 }, |
|
2180 toMinimapCoords: function(_point) { |
|
2181 return _point.multiply(this.minimap.scale).add(this.minimap.offset).add(this.minimap.topleft); |
|
2182 }, |
|
2183 toModelCoords: function(_point) { |
|
2184 return _point.subtract(this.offset).divide(this.scale); |
|
2185 }, |
|
2186 addRepresentation: function(_type, _model) { |
|
2187 var _repr = new Renderer[_type](this, _model); |
|
2188 console.log("REPR RENKAN",_repr); |
|
2189 console.log("REPR RENKAN",Renderer[_type]); |
|
2190 this.representations.push(_repr); |
|
2191 return _repr; |
|
2192 }, |
|
2193 addRepresentations: function(_type, _collection) { |
|
2194 var _this = this; |
|
2195 _collection.forEach(function(_model) { |
|
2196 _this.addRepresentation(_type, _model); |
|
2197 }); |
|
2198 }, |
|
2199 userTemplate: _.template( |
|
2200 '<li class="Rk-User"><span class="Rk-UserColor" style="background:<%=background%>;"></span><%=name%></li>' |
|
2201 ), |
|
2202 redrawUsers: function() { |
|
2203 if (!this.renkan.options.show_user_list) { |
|
2204 return; |
|
2205 } |
|
2206 var allUsers = [].concat((this.renkan.project.current_user_list || {}).models || [], (this.renkan.project.get("users") || {}).models || []), |
|
2207 ulistHtml = '', |
|
2208 $userpanel = this.$.find(".Rk-Users"), |
|
2209 $name = $userpanel.find(".Rk-CurrentUser-Name"), |
|
2210 $cpitems = $userpanel.find(".Rk-Edit-ColorPicker li"), |
|
2211 $colorsquare = $userpanel.find(".Rk-CurrentUser-Color"), |
|
2212 _this = this; |
|
2213 $name.off("click").text(this.renkan.translate("<unknown user>")); |
|
2214 $cpitems.off("mouseleave click"); |
|
2215 allUsers.forEach(function(_user) { |
|
2216 if (_user.get("_id") === _this.renkan.current_user) { |
|
2217 $name.text(_user.get("title")); |
|
2218 $colorsquare.css("background", _user.get("color")); |
|
2219 if (_this.isEditable()) { |
|
2220 |
|
2221 if (_this.renkan.options.user_name_editable) { |
|
2222 $name.click(function() { |
|
2223 var $this = $(this), |
|
2224 $input = $('<input>').val(_user.get("title")).blur(function() { |
|
2225 _user.set("title", $(this).val()); |
|
2226 _this.redrawUsers(); |
|
2227 _this.redraw(); |
|
2228 }); |
|
2229 $this.empty().html($input); |
|
2230 $input.select(); |
|
2231 }); |
|
2232 } |
|
2233 |
|
2234 if (_this.renkan.options.user_color_editable) { |
|
2235 $cpitems.click( |
|
2236 function(_e) { |
|
2237 _e.preventDefault(); |
|
2238 if (_this.isEditable()) { |
|
2239 _user.set("color", $(this).attr("data-color")); |
|
2240 } |
|
2241 $(this).parent().hide(); |
|
2242 } |
|
2243 ).mouseleave(function() { |
|
2244 $colorsquare.css("background", _user.get("color")); |
|
2245 }); |
|
2246 } |
|
2247 } |
|
2248 |
|
2249 } else { |
|
2250 ulistHtml += _this.userTemplate({ |
|
2251 name: _user.get("title"), |
|
2252 background: _user.get("color") |
|
2253 }); |
|
2254 } |
|
2255 }); |
|
2256 $userpanel.find(".Rk-UserList").html(ulistHtml); |
|
2257 }, |
|
2258 removeRepresentation: function(_representation) { |
|
2259 _representation.destroy(); |
|
2260 this.representations = _(this.representations).reject( |
|
2261 function(_repr) { |
|
2262 return _repr == _representation; |
|
2263 } |
|
2264 ); |
|
2265 }, |
|
2266 getRepresentationByModel: function(_model) { |
|
2267 if (!_model) { |
|
2268 return undefined; |
|
2269 } |
|
2270 return _(this.representations).find(function(_repr) { |
|
2271 return _repr.model === _model; |
|
2272 }); |
|
2273 }, |
|
2274 removeRepresentationsOfType: function(_type) { |
|
2275 var _representations = _(this.representations).filter(function(_repr) { |
|
2276 return _repr.type == _type; |
|
2277 }), |
|
2278 _this = this; |
|
2279 _(_representations).each(function(_repr) { |
|
2280 _this.removeRepresentation(_repr); |
|
2281 }); |
|
2282 }, |
|
2283 highlightModel: function(_model) { |
|
2284 var _repr = this.getRepresentationByModel(_model); |
|
2285 if (_repr) { |
|
2286 _repr.highlight(); |
|
2287 } |
|
2288 }, |
|
2289 unhighlightAll: function(_model) { |
|
2290 _(this.representations).each(function(_repr) { |
|
2291 _repr.unhighlight(); |
|
2292 }); |
|
2293 }, |
|
2294 unselectAll: function(_model) { |
|
2295 _(this.representations).each(function(_repr) { |
|
2296 _repr.unselect(); |
|
2297 }); |
|
2298 }, |
|
2299 redraw: function() { |
|
2300 _(this.representations).each(function(_representation) { |
|
2301 _representation.redraw(true); |
|
2302 }); |
|
2303 if (this.minimap) { |
|
2304 this.redrawMiniframe(); |
|
2305 } |
|
2306 paper.view.draw(); |
|
2307 }, |
|
2308 addTempEdge: function(_from, _point) { |
|
2309 var _tmpEdge = this.addRepresentation("TempEdge",null); |
|
2310 _tmpEdge.end_pos = _point; |
|
2311 _tmpEdge.from_representation = _from; |
|
2312 _tmpEdge.redraw(); |
|
2313 this.click_target = _tmpEdge; |
|
2314 }, |
|
2315 findTarget: function(_hitResult) { |
|
2316 if (_hitResult && typeof _hitResult.item.__representation !== "undefined") { |
|
2317 var _newTarget = _hitResult.item.__representation; |
|
2318 if (this.selected_target !== _hitResult.item.__representation) { |
|
2319 if (this.selected_target) { |
|
2320 this.selected_target.unselect(_newTarget); |
|
2321 } |
|
2322 _newTarget.select(this.selected_target); |
|
2323 this.selected_target = _newTarget; |
|
2324 } |
|
2325 } else { |
|
2326 if (this.selected_target) { |
|
2327 this.selected_target.unselect(); |
|
2328 } |
|
2329 this.selected_target = null; |
|
2330 } |
|
2331 }, |
|
2332 paperShift: function(_delta) { |
|
2333 this.offset = this.offset.add(_delta); |
|
2334 this.redraw(); |
|
2335 }, |
|
2336 onMouseMove: function(_event) { |
|
2337 var _off = this.canvas_$.offset(), |
|
2338 _point = new paper.Point([ |
|
2339 _event.pageX - _off.left, |
|
2340 _event.pageY - _off.top |
|
2341 ]), |
|
2342 _delta = _point.subtract(this.last_point); |
|
2343 this.last_point = _point; |
|
2344 if (!this.is_dragging && this.mouse_down && _delta.length > Rkns.Utils._MIN_DRAG_DISTANCE) { |
|
2345 this.is_dragging = true; |
|
2346 } |
|
2347 var _hitResult = paper.project.hitTest(_point); |
|
2348 if (this.is_dragging) { |
|
2349 if (this.click_target && typeof this.click_target.paperShift === "function") { |
|
2350 this.click_target.paperShift(_delta); |
|
2351 } else { |
|
2352 this.paperShift(_delta); |
|
2353 } |
|
2354 } else { |
|
2355 this.findTarget(_hitResult); |
|
2356 } |
|
2357 paper.view.draw(); |
|
2358 }, |
|
2359 onMouseDown: function(_event, _isTouch) { |
|
2360 var _off = this.canvas_$.offset(), |
|
2361 _point = new paper.Point([ |
|
2362 _event.pageX - _off.left, |
|
2363 _event.pageY - _off.top |
|
2364 ]); |
|
2365 this.last_point = _point; |
|
2366 this.mouse_down = true; |
|
2367 if (!this.click_target || this.click_target.type !== "Temp-edge") { |
|
2368 this.removeRepresentationsOfType("editor"); |
|
2369 this.is_dragging = false; |
|
2370 var _hitResult = paper.project.hitTest(_point); |
|
2371 if (_hitResult && typeof _hitResult.item.__representation !== "undefined") { |
|
2372 this.click_target = _hitResult.item.__representation; |
|
2373 this.click_target.mousedown(_event, _isTouch); |
|
2374 } else { |
|
2375 this.click_target = null; |
|
2376 if (this.isEditable() && this.click_mode === Rkns.Utils._CLICKMODE_ADDNODE) { |
|
2377 var _coords = this.toModelCoords(_point), |
|
2378 _data = { |
|
2379 id: Rkns.Utils.getUID('node'), |
|
2380 created_by: this.renkan.current_user, |
|
2381 position: { |
|
2382 x: _coords.x, |
|
2383 y: _coords.y |
|
2384 } |
|
2385 }; |
|
2386 _node = this.renkan.project.addNode(_data); |
|
2387 this.getRepresentationByModel(_node).openEditor(); |
|
2388 } |
|
2389 } |
|
2390 } |
|
2391 if (this.click_mode) { |
|
2392 if (this.isEditable() && this.click_mode === Rkns.Utils._CLICKMODE_STARTEDGE && this.click_target && this.click_target.type === "Node") { |
|
2393 this.removeRepresentationsOfType("editor"); |
|
2394 this.addTempEdge(this.click_target, _point); |
|
2395 this.click_mode = Rkns.Utils._CLICKMODE_ENDEDGE; |
|
2396 this.notif_$.fadeOut(function() { |
|
2397 $(this).html(this.renkan.translate("Click on a second node to complete the edge")).fadeIn(); |
|
2398 }); |
|
2399 } else { |
|
2400 this.notif_$.hide(); |
|
2401 this.click_mode = false; |
|
2402 } |
|
2403 } |
|
2404 paper.view.draw(); |
|
2405 }, |
|
2406 onMouseUp: function(_event, _isTouch) { |
|
2407 this.mouse_down = false; |
|
2408 if (this.click_target) { |
|
2409 var _off = this.canvas_$.offset(); |
|
2410 this.click_target.mouseup( |
|
2411 { |
|
2412 point: new paper.Point([ |
|
2413 _event.pageX - _off.left, |
|
2414 _event.pageY - _off.top |
|
2415 ]) |
|
2416 }, |
|
2417 _isTouch |
|
2418 ); |
|
2419 } else { |
|
2420 this.click_target = null; |
|
2421 this.is_dragging = false; |
|
2422 if (_isTouch) { |
|
2423 this.unselectAll(); |
|
2424 } |
|
2425 } |
|
2426 paper.view.draw(); |
|
2427 }, |
|
2428 onScroll: function(_event, _scrolldelta) { |
|
2429 this.totalScroll += _scrolldelta; |
|
2430 if (Math.abs(this.totalScroll) >= 1) { |
|
2431 var _off = this.canvas_$.offset(), |
|
2432 _delta = new paper.Point([ |
|
2433 _event.pageX - _off.left, |
|
2434 _event.pageY - _off.top |
|
2435 ]).subtract(this.offset).multiply( Math.SQRT2 - 1 ); |
|
2436 if (this.totalScroll > 0) { |
|
2437 this.setScale( this.scale * Math.SQRT2, this.offset.subtract(_delta) ); |
|
2438 } else { |
|
2439 this.setScale( this.scale * Math.SQRT1_2, this.offset.add(_delta.divide(Math.SQRT2))); |
|
2440 } |
|
2441 this.totalScroll = 0; |
|
2442 } |
|
2443 }, |
|
2444 onDoubleClick: function(_event) { |
|
2445 if (!this.isEditable()) { |
|
2446 return; |
|
2447 } |
|
2448 var _off = this.canvas_$.offset(), |
|
2449 _point = new paper.Point([ |
|
2450 _event.pageX - _off.left, |
|
2451 _event.pageY - _off.top |
|
2452 ]); |
|
2453 var _hitResult = paper.project.hitTest(_point); |
|
2454 if (this.isEditable() && (!_hitResult || typeof _hitResult.item.__representation === "undefined")) { |
|
2455 var _coords = this.toModelCoords(_point), |
|
2456 _data = { |
|
2457 id: Rkns.Utils.getUID('node'), |
|
2458 created_by: this.renkan.current_user, |
|
2459 position: { |
|
2460 x: _coords.x, |
|
2461 y: _coords.y |
|
2462 } |
|
2463 }, |
|
2464 _node = this.renkan.project.addNode(_data); |
|
2465 this.getRepresentationByModel(_node).openEditor(); |
|
2466 } |
|
2467 paper.view.draw(); |
|
2468 }, |
|
2469 defaultDropHandler: function(_data) { |
|
2470 var newNode = {}; |
|
2471 switch(_data["text/x-iri-specific-site"]) { |
|
2472 case "twitter": |
|
2473 var snippet = $('<div>').html(_data["text/x-iri-selected-html"]), |
|
2474 tweetdiv = snippet.find(".tweet"); |
|
2475 newNode.title = this.renkan.translate("Tweet by ") + tweetdiv.attr("data-name"); |
|
2476 newNode.uri = "http://twitter.com/" + tweetdiv.attr("data-screen-name") + "/status/" + tweetdiv.attr("data-tweet-id"); |
|
2477 newNode.image = tweetdiv.find(".avatar").attr("src"); |
|
2478 newNode.description = tweetdiv.find(".js-tweet-text:first").text(); |
|
2479 break; |
|
2480 case "google": |
|
2481 var snippet = $('<div>').html(_data["text/x-iri-selected-html"]); |
|
2482 newNode.title = snippet.find("h3:first").text().trim(); |
|
2483 newNode.uri = snippet.find("h3 a").attr("href"); |
|
2484 newNode.description = snippet.find(".st:first").text().trim(); |
|
2485 break; |
|
2486 case undefined: |
|
2487 default: |
|
2488 if (_data["text/x-iri-source-uri"]) { |
|
2489 newNode.uri = _data["text/x-iri-source-uri"]; |
|
2490 } |
|
2491 if (_data["text/plain"] || _data["text/x-iri-selected-text"]) { |
|
2492 newNode.description = (_data["text/plain"] || _data["text/x-iri-selected-text"]).replace(/[\s\n]+/gm,' ').trim(); |
|
2493 } |
|
2494 if (_data["text/html"] || _data["text/x-iri-selected-html"]) { |
|
2495 var snippet = $('<div>').html(_data["text/html"] || _data["text/x-iri-selected-html"]); |
|
2496 var _svgimgs = snippet.find("image"); |
|
2497 if (_svgimgs.length) { |
|
2498 newNode.image = _svgimgs.attr("xlink:href"); |
|
2499 } |
|
2500 var _svgpaths = snippet.find("path"); |
|
2501 if (_svgpaths.length) { |
|
2502 newNode.clipPath = _svgpaths.attr("d"); |
|
2503 } |
|
2504 var _imgs = snippet.find("img"); |
|
2505 if (_imgs.length) { |
|
2506 newNode.image = _imgs[0].src; |
|
2507 } |
|
2508 var _as = snippet.find("a"); |
|
2509 if (_as.length) { |
|
2510 newNode.uri = _as[0].href; |
|
2511 } |
|
2512 newNode.title = snippet.find("[title]").attr("title") || newNode.title; |
|
2513 newNode.description = snippet.text().replace(/[\s\n]+/gm,' ').trim(); |
|
2514 } |
|
2515 if (_data["text/uri-list"]) { |
|
2516 newNode.uri = _data["text/uri-list"]; |
|
2517 } |
|
2518 if (_data["text/x-moz-url"] && !newNode.title) { |
|
2519 newNode.title = (_data["text/x-moz-url"].split("\n")[1] || "").trim(); |
|
2520 if (newNode.title === newNode.uri) { |
|
2521 newNode.title = false; |
|
2522 } |
|
2523 } |
|
2524 if (_data["text/x-iri-source-title"] && !newNode.title) { |
|
2525 newNode.title = _data["text/x-iri-source-title"]; |
|
2526 } |
|
2527 if (_data["text/html"] || _data["text/x-iri-selected-html"]) { |
|
2528 var snippet = $('<div>').html(_data["text/html"] || _data["text/x-iri-selected-html"]); |
|
2529 newNode.image = snippet.find("[data-image]").attr("data-image") || newNode.image; |
|
2530 newNode.uri = snippet.find("[data-uri]").attr("data-uri") || newNode.uri; |
|
2531 newNode.title = snippet.find("[data-title]").attr("data-title") || newNode.title; |
|
2532 newNode.description = snippet.find("[data-description]").attr("data-description") || newNode.description; |
|
2533 newNode.clipPath = snippet.find("[data-clip-path]").attr("data-clip-path") || newNode.clipPath; |
|
2534 } |
|
2535 } |
|
2536 |
|
2537 if(typeof this.renkan.options.drop_enhancer === "function"){ |
|
2538 newNode = this.renkan.options.drop_enhancer(newNode, _data); |
|
2539 } |
|
2540 return newNode; |
|
2541 |
|
2542 }, |
|
2543 dropData: function(_data, _event) { |
|
2544 if (!this.isEditable()) { |
|
2545 return; |
|
2546 } |
|
2547 if (_data["text/json"] || _data["application/json"]) { |
|
2548 try { |
|
2549 var jsondata = JSON.parse(_data["text/json"] || _data["application/json"]); |
|
2550 _(_data).extend(jsondata); |
|
2551 } |
|
2552 catch(e) {} |
|
2553 } |
|
2554 |
|
2555 var newNode = (typeof this.renkan.options.drop_handler === "undefined")?this.defaultDropHandler(_data):this.renkan.options.drop_handler(_data); |
|
2556 |
|
2557 if (!newNode.title) { |
|
2558 newNode.title = this.renkan.translate("Dragged resource"); |
|
2559 } |
|
2560 var fields = ["title", "description", "uri", "image"]; |
|
2561 for (var i = 0; i < fields.length; i++) { |
|
2562 var f = fields[i]; |
|
2563 if (_data["text/x-iri-" + f] || _data[f]) { |
|
2564 newNode[f] = _data["text/x-iri-" + f] || _data[f]; |
|
2565 } |
|
2566 if (newNode[f] === "none" || newNode[f] === "null") { |
|
2567 newNode[f] = undefined; |
|
2568 } |
|
2569 } |
|
2570 var _off = this.canvas_$.offset(), |
|
2571 _point = new paper.Point([ |
|
2572 _event.pageX - _off.left, |
|
2573 _event.pageY - _off.top |
|
2574 ]), |
|
2575 _coords = this.toModelCoords(_point), |
|
2576 _nodedata = { |
|
2577 id: Rkns.Utils.getUID('node'), |
|
2578 created_by: this.renkan.current_user, |
|
2579 uri: newNode.uri || "", |
|
2580 title: newNode.title || "", |
|
2581 description: newNode.description || "", |
|
2582 image: newNode.image || "", |
|
2583 color: newNode.color || undefined, |
|
2584 clip_path: newNode.clipPath || undefined, |
|
2585 position: { |
|
2586 x: _coords.x, |
|
2587 y: _coords.y |
|
2588 } |
|
2589 }; |
|
2590 var _node = this.renkan.project.addNode(_nodedata), |
|
2591 _repr = this.getRepresentationByModel(_node); |
|
2592 if (_event.type === "drop") { |
|
2593 _repr.openEditor(); |
|
2594 } |
|
2595 }, |
|
2596 fullScreen: function() { |
|
2597 var _isFull = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen, |
|
2598 _el = this.renkan.$[0], |
|
2599 _requestMethods = ["requestFullScreen","mozRequestFullScreen","webkitRequestFullScreen"], |
|
2600 _cancelMethods = ["cancelFullScreen","mozCancelFullScreen","webkitCancelFullScreen"]; |
|
2601 if (_isFull) { |
|
2602 for (var i = 0; i < _cancelMethods.length; i++) { |
|
2603 if (typeof document[_cancelMethods[i]] === "function") { |
|
2604 document[_cancelMethods[i]](); |
|
2605 break; |
|
2606 } |
|
2607 } |
|
2608 } else { |
|
2609 for (var i = 0; i < _requestMethods.length; i++) { |
|
2610 if (typeof _el[_requestMethods[i]] === "function") { |
|
2611 _el[_requestMethods[i]](); |
|
2612 break; |
|
2613 } |
|
2614 } |
|
2615 } |
|
2616 }, |
|
2617 zoomOut: function() { |
|
2618 var _newScale = this.scale * Math.SQRT1_2, |
|
2619 _offset = new paper.Point([ |
|
2620 this.canvas_$.width(), |
|
2621 this.canvas_$.height() |
|
2622 ]).multiply( .5 * ( 1 - Math.SQRT1_2 ) ).add(this.offset.multiply( Math.SQRT1_2 )); |
|
2623 this.setScale( _newScale, _offset ); |
|
2624 }, |
|
2625 zoomIn: function() { |
|
2626 var _newScale = this.scale * Math.SQRT2, |
|
2627 _offset = new paper.Point([ |
|
2628 this.canvas_$.width(), |
|
2629 this.canvas_$.height() |
|
2630 ]).multiply( .5 * ( 1 - Math.SQRT2 ) ).add(this.offset.multiply( Math.SQRT2 )); |
|
2631 this.setScale( _newScale, _offset ); |
|
2632 }, |
|
2633 addNodeBtn: function() { |
|
2634 if (this.click_mode === Rkns.Utils._CLICKMODE_ADDNODE) { |
|
2635 this.click_mode = false; |
|
2636 this.notif_$.hide(); |
|
2637 } else { |
|
2638 this.click_mode = Rkns.Utils._CLICKMODE_ADDNODE; |
|
2639 this.notif_$.text(this.renkan.translate("Click on the background canvas to add a node")).fadeIn(); |
|
2640 } |
|
2641 return false; |
|
2642 }, |
|
2643 addEdgeBtn: function() { |
|
2644 if (this.click_mode === Rkns.Utils._CLICKMODE_STARTEDGE || this.click_mode === Rkns.Utils._CLICKMODE_ENDEDGE) { |
|
2645 this.click_mode = false; |
|
2646 this.notif_$.hide(); |
|
2647 } else { |
|
2648 this.click_mode = Rkns.Utils._CLICKMODE_STARTEDGE; |
|
2649 this.notif_$.text(this.renkan.translate("Click on a first node to start the edge")).fadeIn(); |
|
2650 } |
|
2651 return false; |
|
2652 }, |
|
2653 foldBins: function() { |
|
2654 var foldBinsButton = this.$.find(".Rk-Fold-Bins"), |
|
2655 bins = this.renkan.$.find(".Rk-Bins"); |
|
2656 if (bins.offset().left < 0) { |
|
2657 bins.animate({left: 0},250); |
|
2658 var _this = this; |
|
2659 this.$.animate({left: 300},250,function() { |
|
2660 var w = _this.$.width(); |
|
2661 paper.view.viewSize = new paper.Size([w, _this.canvas_$.height()]); |
|
2662 }); |
|
2663 foldBinsButton.html("«"); |
|
2664 } else { |
|
2665 bins.animate({left: -300},250); |
|
2666 var _this = this; |
|
2667 this.$.animate({left: 0},250,function() { |
|
2668 var w = _this.$.width(); |
|
2669 paper.view.viewSize = new paper.Size([w, _this.canvas_$.height()]); |
|
2670 }); |
|
2671 foldBinsButton.html("»"); |
|
2672 } |
|
2673 }, |
|
2674 save: function() { }, |
|
2675 open: function() { } |
|
2676 }); |
|
2677 })(window); |
|
2678 |
|
2679 /* END paper-renderer.js */ |
|