4afc95588cc5b0e16e21ed83ec1221303a5e587a
2 Copyright 2017 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
3 Copyright 2018 EveryUP srl
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
9 http://www.apache.org/licenses/LICENSE-2.0
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
17 if (typeof TCD3
=== 'undefined') {
21 TCD3
.ModelGraphEditor
= (function () {
25 var SHIFT_BUTTON
= 16;
26 var IMAGE_PATH
= "/static/assets/img/";
29 ModelGraphEditor
.prototype = new TCD3
.GraphEditor();
30 ModelGraphEditor
.prototype.constructor = ModelGraphEditor
;
31 ModelGraphEditor
.prototype.parent
= TCD3
.GraphEditor
.prototype;
36 function ModelGraphEditor(args
) {
43 ModelGraphEditor
.prototype.init = function (args
) {
44 this.parent
.init
.call(this, args
);
46 this.desc_id
= args
.desc_id
|| undefined; //TODO remove it
48 this.type_property
= {};
49 this.type_property
["unrecognized"] = args
.gui_properties
["nodes"]["default"];
51 this._edit_mode
= args
.edit_mode
|| false;
53 Object
.keys(args
.gui_properties
["nodes"]).forEach(function (key
, index
) {
55 this.type_property
[key
] = args
.gui_properties
["nodes"][key
];
57 this.type_property
[key
]["shape"] = this.parent
.get_d3_symbol(this.type_property
[key
]["shape"]);
58 if (this.type_property
[key
]["image"] !== undefined) {
59 this.type_property
[key
]["image"] = IMAGE_PATH
+ this.type_property
[key
]["image"];
64 if (args
.gui_properties
["edges"]) {
65 this.type_property_link
= args
.gui_properties
["edges"];
66 var link_types
= ['unrecognized'].concat(Object
.keys(self
.type_property_link
))
67 this.defs
.selectAll("marker")
70 .append("svg:marker") // This section adds in the arrows
71 .attr("id", function (d
) {
74 .attr("viewBox", "-5 -5 10 10")
75 .attr("refX", 13) /*must be smarter way to calculate shift*/
77 .attr("markerUnits", "userSpaceOnUse")
78 .attr("markerWidth", 12)
79 .attr("markerHeight", 12)
80 .attr("orient", "auto")
82 .attr("d", "M 0,0 m -5,-5 L 5,0 L -5,5 Z")
83 .attr('fill', function (d
) {
84 return self
.type_property_link
[d
].color
;
88 this.customBehavioursOnEvents
= args
.behaviorsOnEvents
|| undefined;
91 var data_url
= args
.data_url
|| undefined;
92 if (!args
.graph_data
&& args
.data_url
) {
93 d3
.json(data_url
, function (error
, data
) {
94 //console.log(JSON.stringify(data))
95 self
.d3_graph
.nodes
= data
.vertices
;
96 self
.d3_graph
.links
= data
.edges
;
97 self
.d3_graph
.graph_parameters
= data
.graph_parameters
;
98 self
.model
= data
.model
;
99 self
.refreshGraphParameters(self
.d3_graph
.graph_parameters
);
102 //if(args.filter_base != undefined)
104 setTimeout(function () {
105 self
.handleForce(true);
106 self
.handleFiltersParams(args
.filter_base
);
111 this.updateData(args
)
116 * Update data of the graph.
117 * @param {Object} Required. An object that specifies tha data of the new node.
120 ModelGraphEditor
.prototype.updateData = function (args
) {
121 this.d3_graph
.nodes
= args
.vertices
;
122 this.d3_graph
.links
= args
.edges
;
123 this.d3_graph
.graph_parameters
= args
.graph_parameters
;
124 this.model
= args
.model
;
125 this.refreshGraphParameters(this.d3_graph
.graph_parameters
);
129 this.handleForce(this.forceSimulationActive
);
130 //this.force.restart();
131 //if(args.filter_base != undefined)
133 if(args
.filter_base
){
135 setTimeout(function () {
136 self
.handleForce(true);
137 self
.handleFiltersParams(args
.filter_base
);
143 * Add a new node to the graph.
144 * @param {Object} Required. An object that specifies tha data of the new node.
147 ModelGraphEditor
.prototype.addNode = function (node
, success
, error
) {
149 var current_layer
= self
.getCurrentView();
150 var node_type
= node
.info
.type
;
151 if (self
.model
.layer
[current_layer
] && self
.model
.layer
[current_layer
].nodes
[node_type
] && self
.model
.layer
[current_layer
].nodes
[node_type
].addable
) {
152 if (self
.model
.layer
[current_layer
].nodes
[node_type
].addable
.callback
) {
153 console
.log(self
.model
.callback
)
154 var c
= self
.model
.callback
[self
.model
.layer
[current_layer
].nodes
[node_type
].addable
.callback
].class;
155 var controller
= new TCD3
.OsmController();
156 controller
[self
.model
.layer
[current_layer
].nodes
[node_type
].addable
.callback
](self
, node
, function (result
) {
159 self
.updateData(result
);
160 // self.parent.addNode.call(self, node);
161 success
&& success();
166 log('addNode: callback undefined in model spec.');
167 error
&& error("You can't add a " + node
.info
.type
+ ", callback undefined.");
170 //FIXME Error handling????
171 log("You can't add a " + node
.info
.type
+ " in a current layer " + current_layer
);
172 error
&& error("You can't add a " + node
.info
.type
+ " in a current layer " + current_layer
);
178 * Update the data properties of the node
179 * @param {Object} Required. An object that specifies tha data of the node.
182 ModelGraphEditor
.prototype.updateDataNode = function (node
, args
, success
, error
) {
185 var controller
= new TCD3
.OsmController();
186 controller
.updateNode(this,node
, args
, function(result
){
187 self
.updateData(result
);
188 success
&& success();
193 * Update the data properties of the node
194 * @param {Object} Required. An object that specifies tha data of the node.
197 ModelGraphEditor
.prototype.updateGraphParams = function (args
, success
, error
) {
198 var controller
= new TCD3
.OsmController();
199 controller
.updateGraphParams(args
, function(){
200 success
&& success();
205 * Remove a node from graph and related links.
206 * @param {String} Required. Id of node to remove.
209 ModelGraphEditor
.prototype.removeNode = function (node
, success
, error
) {
210 console
.log('removeNode', JSON
.stringify(node
))
212 var current_layer
= self
.getCurrentView();
213 var node_type
= node
.info
.type
;
214 if (node
.info
.desc_id
== undefined) {
215 node
.info
.desc_id
= self
.desc_id
;
217 if (self
.model
.layer
[current_layer
] && self
.model
.layer
[current_layer
].nodes
[node_type
] && self
.model
.layer
[current_layer
].nodes
[node_type
].removable
) {
218 if (self
.model
.layer
[current_layer
].nodes
[node_type
].removable
.callback
) {
219 var c
= self
.model
.callback
[self
.model
.layer
[current_layer
].nodes
[node_type
].removable
.callback
].class;
220 var controller
= new TCD3
.OsmController();
221 controller
[self
.model
.layer
[current_layer
].nodes
[node_type
].removable
.callback
](self
, node
, function () {
222 self
.parent
.removeNode
.call(self
, node
);
223 success
&& success();
227 log('removeNode: callback undefined in model spec.');
228 error
&& error("You can't remove a " + node
.info
.type
+ ", callback undefined.");
231 //FIXME we need to manage alert in a different way: FAILBACK
232 log("You can't remove a " + node
.info
.type
);
233 error
&& error("You can't remove a " + node
.info
.type
);
238 * Add a new link to graph.
239 * @param {Object} Required. An object that specifies tha data of the new Link.
242 ModelGraphEditor
.prototype.addLink = function (s
, d
, success
, error
) {
244 var source_id
= s
.id
;
245 var target_id
= d
.id
;
246 var source_type
= s
.info
.type
;
247 var destination_type
= d
.info
.type
;
251 view
: this.filter_parameters
.link
.view
[0],
252 group
: this.filter_parameters
.link
.group
,
253 desc_id
: this.desc_id
255 log("addLink: " + JSON
.stringify(link
))
256 var current_layer
= self
.getCurrentView()
257 if (self
.model
.layer
[current_layer
].allowed_edges
&& self
.model
.layer
[current_layer
].allowed_edges
[source_type
] && self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
]) {
259 if (self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].callback
) {
260 var callback
= self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].callback
;
261 console
.log(callback
, self
.model
.callback
)
262 var direct_edge
= 'direct_edge' in self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
] ? self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
]['direct_edge'] : false;
263 link
.directed_edge
= direct_edge
;
264 var c
= self
.model
.callback
[callback
].class;
265 var controller
= new TCD3
.OsmController();
266 controller
[callback
](self
, link
, function () {
267 self
._deselectAllNodes();
268 self
.parent
.addLink
.call(self
, link
);
273 log('addLink: callback undefined in model spec.');
274 error
&& error("You can't add a link, callback undefined.");
278 //FIXME we need to manage alert in a different way: FAILBACK
279 log("You can't link a " + source_type
+ " with a " + destination_type
);
281 error
&& error("You can't link a " + source_type
+ " with a " + destination_type
);
286 * Remove a link from graph.
287 * @param {String} Required. The identifier of link to remove.
290 ModelGraphEditor
.prototype.removeLink = function (link
, success
, error
) {
294 var source_type
= s
.info
.type
;
295 var destination_type
= d
.info
.type
;
296 var current_layer
= self
.getCurrentView();
297 if (self
.model
.layer
[current_layer
].allowed_edges
&& self
.model
.layer
[current_layer
].allowed_edges
[source_type
] && self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
] &&
298 self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].removable
300 if (self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].removable
.callback
) {
301 var callback
= self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].removable
.callback
;
302 var c
= self
.model
.callback
[callback
].class;
303 var controller
= new TCD3
.OsmController();
304 controller
[callback
](self
, link
, function () {
305 self
._deselectAllNodes();
306 self
._deselectAllLinks();
307 self
.parent
.removeLink
.call(self
, link
.index
);
308 success
&& success();
311 log('removeLink: callback undefined in model spec.');
312 error
&& error("You can't remove a link, callback undefined.");
316 //FIXME we need to manage alert in a different way: FAILBACK
317 log("You can't delete the link");
318 error
&& error("You can't delete the link");
325 ModelGraphEditor
.prototype.savePositions = function (data
) {
327 this.node
.each(function (d
) {
329 vertices
[d
.id
]['x'] = d
.x
;
330 vertices
[d
.id
]['y'] = d
.y
;
332 new TCD3
.GraphRequests().savePositions({
342 ModelGraphEditor
.prototype._setupBehaviorsOnEvents = function (layer
) {
345 var contextMenuLinksAction
= [{
346 title
: 'Delete Link',
347 action: function (elm
, link
, i
) {
348 self
.removeLink(link
, null, showAlert
);
352 var contextMenuNodesAction
= [
355 action: function (elm
, d
, i
) {
356 self
.removeNode(d
, null, showAlert
);
362 if (this.customBehavioursOnEvents
) {
363 contextMenuNodesAction
= contextMenuNodesAction
.concat(this.customBehavioursOnEvents
['behaviors'].nodes
);
367 if (self
.model
&& self
.model
.layer
&& self
.model
.layer
[layer
] && self
.model
.layer
[layer
].action
&& self
.model
.layer
[layer
].action
.node
) {
368 for (var i
in self
.model
.layer
[layer
].action
.node
) {
369 var action
= self
.model
.layer
[layer
].action
.node
[i
]
370 contextMenuNodesAction
.push({
372 action: function (elm
, d
, i
) {
373 var callback
= action
.callback
;
374 var c
= self
.model
.callback
[callback
].class;
375 var controller
= new TCD3
[c
]();
382 controller
[callback
](self
, args
);
384 edit_mode
: (action
.edit_mode
!== undefined) ? action
.edit_mode
: undefined
389 this.behavioursOnEvents
= {
391 'click': function (d
) {
393 d3
.event
.preventDefault();
395 if (self
._edit_mode
&& self
.lastKeyDown
=== SHIFT_BUTTON
&& self
._selected_node
!== undefined) {
396 self
.addLink(self
._selected_node
, d
, null, showAlert
);
398 self
._selectNodeExclusive(this, d
);
402 'mouseover': function (d
) {
403 self
.link
.style('stroke-width', function (l
) {
404 if (d
=== l
.source
|| d
=== l
.target
)
410 'mouseout': function (d
) {
411 self
.link
.style('stroke-width', 2);
413 'contextmenu': d3
.contextMenu(contextMenuNodesAction
, {
414 'edit_mode': self
._edit_mode
,
416 'type_object': 'node'
420 'click': function (d
) {
421 self
._selectLinkExclusive(this, d
);
423 'dblclick': function (event
) {
426 'mouseover': function (d
) {
427 d3
.select(this).style('stroke-width', 4);
429 'mouseout': function (d
) {
430 if (d
!== self
._selected_link
)
431 d3
.select(this).style('stroke-width', 2);
433 'contextmenu': d3
.contextMenu(contextMenuLinksAction
, {
434 'edit_mode': self
._edit_mode
,
436 'type_object': 'link'
442 ModelGraphEditor
.prototype.handleFiltersParams = function (filtersParams
, notFireEvent
) {
444 this.parent
.handleFiltersParams
.call(this, filtersParams
, notFireEvent
);
445 if (filtersParams
&& filtersParams
.link
&& filtersParams
.link
.view
)
446 this._setupBehaviorsOnEvents(filtersParams
.link
.view
[0]);
449 ModelGraphEditor
.prototype.getAvailableNodes = function () {
450 log('getAvailableNodes');
452 if (this.model
&& this.model
.layer
[this.getCurrentView()] !== undefined)
453 return this.model
.layer
[this.getCurrentView()].nodes
;
458 ModelGraphEditor
.prototype.getTypeProperty = function () {
459 return this.type_property
;
462 ModelGraphEditor
.prototype.getCurrentGroup = function () {
463 return this.filter_parameters
.node
.group
[0];
466 ModelGraphEditor
.prototype.getCurrentView = function () {
467 return this.filter_parameters
.link
.view
[0];
469 ModelGraphEditor
.prototype.getCurrentFilters = function () {
470 return this.filter_parameters
;
473 ModelGraphEditor
.prototype.getGraphParams = function () {
474 return this.d3_graph
.graph_parameters
;
482 console
.log("::ModelGraphEditor::", text
);
486 return ModelGraphEditor
;
491 if (typeof module
=== 'object') {
492 module
.exports
= TCD3
.ModelGraphEditor
;