4ec7650e608ad8c1169b1f70130b0c1537506dbe
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
) {
199 var controller
= new TCD3
.OsmController();
200 controller
.updateGraphParams(args
, function(result
){
201 self
.updateData(result
);
202 success
&& success();
207 * Remove a node from graph and related links.
208 * @param {String} Required. Id of node to remove.
211 ModelGraphEditor
.prototype.removeNode = function (node
, success
, error
) {
212 console
.log('removeNode', JSON
.stringify(node
))
214 var current_layer
= self
.getCurrentView();
215 var node_type
= node
.info
.type
;
216 if (node
.info
.desc_id
== undefined) {
217 node
.info
.desc_id
= self
.desc_id
;
219 if (self
.model
.layer
[current_layer
] && self
.model
.layer
[current_layer
].nodes
[node_type
] && self
.model
.layer
[current_layer
].nodes
[node_type
].removable
) {
220 if (self
.model
.layer
[current_layer
].nodes
[node_type
].removable
.callback
) {
221 var c
= self
.model
.callback
[self
.model
.layer
[current_layer
].nodes
[node_type
].removable
.callback
].class;
222 var controller
= new TCD3
.OsmController();
223 controller
[self
.model
.layer
[current_layer
].nodes
[node_type
].removable
.callback
](self
, node
, function (result
) {
224 self
._deselectAllNodes();
225 self
.updateData(result
);
226 success
&& success();
230 log('removeNode: callback undefined in model spec.');
231 error
&& error("You can't remove a " + node
.info
.type
+ ", callback undefined.");
234 //FIXME we need to manage alert in a different way: FAILBACK
235 log("You can't remove a " + node
.info
.type
);
236 error
&& error("You can't remove a " + node
.info
.type
);
241 * Add a new link to graph.
242 * @param {Object} Required. An object that specifies tha data of the new Link.
245 ModelGraphEditor
.prototype.addLink = function (s
, d
, success
, error
) {
247 var source_id
= s
.id
;
248 var target_id
= d
.id
;
249 var source_type
= s
.info
.type
;
250 var destination_type
= d
.info
.type
;
254 view
: this.filter_parameters
.link
.view
[0],
255 group
: this.filter_parameters
.link
.group
,
256 desc_id
: this.desc_id
258 log("addLink: " + JSON
.stringify(link
))
259 var current_layer
= self
.getCurrentView()
260 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
]) {
262 if (self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].callback
) {
263 var callback
= self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].callback
;
264 console
.log(callback
, self
.model
.callback
)
265 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;
266 link
.directed_edge
= direct_edge
;
267 var c
= self
.model
.callback
[callback
].class;
268 var controller
= new TCD3
.OsmController();
269 controller
[callback
](self
, link
, function (result
) {
270 self
._deselectAllNodes();
271 self
.updateData(result
);
272 success
&& success();
275 log('addLink: callback undefined in model spec.');
276 error
&& error("You can't add a link, callback undefined.");
280 //FIXME we need to manage alert in a different way: FAILBACK
281 log("You can't link a " + source_type
+ " with a " + destination_type
);
283 error
&& error("You can't link a " + source_type
+ " with a " + destination_type
);
288 * Remove a link from graph.
289 * @param {String} Required. The identifier of link to remove.
292 ModelGraphEditor
.prototype.removeLink = function (link
, success
, error
) {
296 var source_type
= s
.info
.type
;
297 var destination_type
= d
.info
.type
;
298 var current_layer
= self
.getCurrentView();
299 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
] &&
300 self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].removable
302 if (self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].removable
.callback
) {
303 var callback
= self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].removable
.callback
;
304 var c
= self
.model
.callback
[callback
].class;
305 var controller
= new TCD3
.OsmController();
306 controller
[callback
](self
, link
, function () {
307 self
._deselectAllNodes();
308 self
._deselectAllLinks();
309 self
.parent
.removeLink
.call(self
, link
.index
);
310 success
&& success();
313 log('removeLink: callback undefined in model spec.');
314 error
&& error("You can't remove a link, callback undefined.");
318 //FIXME we need to manage alert in a different way: FAILBACK
319 log("You can't delete the link");
320 error
&& error("You can't delete the link");
327 ModelGraphEditor
.prototype.savePositions = function (data
) {
329 this.node
.each(function (d
) {
331 vertices
[d
.id
]['x'] = d
.x
;
332 vertices
[d
.id
]['y'] = d
.y
;
334 new TCD3
.GraphRequests().savePositions({
344 ModelGraphEditor
.prototype._setupBehaviorsOnEvents = function (layer
) {
347 var contextMenuLinksAction
= [{
348 title
: 'Delete Link',
349 action: function (elm
, link
, i
) {
350 self
.removeLink(link
, null, showAlert
);
354 var contextMenuNodesAction
= [
357 action: function (elm
, d
, i
) {
358 self
.removeNode(d
, null, showAlert
);
364 if (this.customBehavioursOnEvents
) {
365 contextMenuNodesAction
= contextMenuNodesAction
.concat(this.customBehavioursOnEvents
['behaviors'].nodes
);
369 if (self
.model
&& self
.model
.layer
&& self
.model
.layer
[layer
] && self
.model
.layer
[layer
].action
&& self
.model
.layer
[layer
].action
.node
) {
370 for (var i
in self
.model
.layer
[layer
].action
.node
) {
371 var action
= self
.model
.layer
[layer
].action
.node
[i
]
372 contextMenuNodesAction
.push({
374 action: function (elm
, d
, i
) {
375 var callback
= action
.callback
;
376 var c
= self
.model
.callback
[callback
].class;
377 var controller
= new TCD3
[c
]();
384 controller
[callback
](self
, args
);
386 edit_mode
: (action
.edit_mode
!== undefined) ? action
.edit_mode
: undefined
391 this.behavioursOnEvents
= {
393 'click': function (d
) {
395 d3
.event
.preventDefault();
397 if (self
._edit_mode
&& self
.lastKeyDown
=== SHIFT_BUTTON
&& self
._selected_node
!== undefined) {
398 self
.addLink(self
._selected_node
, d
, null, showAlert
);
400 self
._selectNodeExclusive(this, d
);
404 'mouseover': function (d
) {
405 self
.link
.style('stroke-width', function (l
) {
406 if (d
=== l
.source
|| d
=== l
.target
)
412 'mouseout': function (d
) {
413 self
.link
.style('stroke-width', 2);
415 'contextmenu': d3
.contextMenu(contextMenuNodesAction
, {
416 'edit_mode': self
._edit_mode
,
418 'type_object': 'node'
422 'click': function (d
) {
423 self
._selectLinkExclusive(this, d
);
425 'dblclick': function (event
) {
428 'mouseover': function (d
) {
429 d3
.select(this).style('stroke-width', 4);
431 'mouseout': function (d
) {
432 if (d
!== self
._selected_link
)
433 d3
.select(this).style('stroke-width', 2);
435 'contextmenu': d3
.contextMenu(contextMenuLinksAction
, {
436 'edit_mode': self
._edit_mode
,
438 'type_object': 'link'
444 ModelGraphEditor
.prototype.handleFiltersParams = function (filtersParams
, notFireEvent
) {
446 this.parent
.handleFiltersParams
.call(this, filtersParams
, notFireEvent
);
447 if (filtersParams
&& filtersParams
.link
&& filtersParams
.link
.view
)
448 this._setupBehaviorsOnEvents(filtersParams
.link
.view
[0]);
451 ModelGraphEditor
.prototype.getAvailableNodes = function () {
452 log('getAvailableNodes');
454 if (this.model
&& this.model
.layer
[this.getCurrentView()] !== undefined)
455 return this.model
.layer
[this.getCurrentView()].nodes
;
460 ModelGraphEditor
.prototype.getTypeProperty = function () {
461 return this.type_property
;
464 ModelGraphEditor
.prototype.getCurrentGroup = function () {
465 return this.filter_parameters
.node
.group
[0];
468 ModelGraphEditor
.prototype.getCurrentView = function () {
469 return this.filter_parameters
.link
.view
[0];
471 ModelGraphEditor
.prototype.getCurrentFilters = function () {
472 return this.filter_parameters
;
475 ModelGraphEditor
.prototype.getGraphParams = function () {
476 return this.d3_graph
.graph_parameters
;
484 console
.log("::ModelGraphEditor::", text
);
488 return ModelGraphEditor
;
493 if (typeof module
=== 'object') {
494 module
.exports
= TCD3
.ModelGraphEditor
;