6cee85d55b6bc3b16785887381a4ac94e7eea1ce
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
.graph_data
.vertices
;
122 this.d3_graph
.links
= args
.graph_data
.edges
;
123 this.d3_graph
.graph_parameters
= args
.graph_data
.graph_parameters
;
124 this.model
= args
.model
;
125 this.refreshGraphParameters(this.d3_graph
.graph_parameters
);
128 //if(args.filter_base != undefined)
130 //if(args.filter_base){
132 setTimeout(function () {
133 self
.handleForce(true);
134 self
.handleFiltersParams(args
.filter_base
);
140 * Add a new node to the graph.
141 * @param {Object} Required. An object that specifies tha data of the new node.
144 ModelGraphEditor
.prototype.addNode = function (node
, success
, error
) {
146 var current_layer
= self
.getCurrentView();
147 var node_type
= node
.info
.type
;
149 if (self
.model
.layer
[current_layer
] && self
.model
.layer
[current_layer
].nodes
[node_type
] && self
.model
.layer
[current_layer
].nodes
[node_type
].addable
) {
150 if (self
.model
.layer
[current_layer
].nodes
[node_type
].addable
.callback
) {
151 var c
= self
.model
.callback
[self
.model
.layer
[current_layer
].nodes
[node_type
].addable
.callback
].class;
152 var controller
= new TCD3
[c
]();
153 controller
[self
.model
.layer
[current_layer
].nodes
[node_type
].addable
.callback
](self
, node
, function () {
154 self
.parent
.addNode
.call(self
, node
);
155 success
&& success();
160 log('addNode: callback undefined in model spec.');
161 error
&& error("You can't add a " + node
.info
.type
+ ", callback undefined.");
164 //FIXME Error handling????
165 log("You can't add a " + node
.info
.type
+ " in a current layer " + current_layer
);
166 error
&& error("You can't add a " + node
.info
.type
+ " in a current layer " + current_layer
);
172 * Update the data properties of the node
173 * @param {Object} Required. An object that specifies tha data of the node.
176 ModelGraphEditor
.prototype.updateDataNode = function (args
) {
177 //FIXME updating a node properties need commit to server side!
178 this.parent
.updateDataNode
.call(this, args
);
182 * Remove a node from graph and related links.
183 * @param {String} Required. Id of node to remove.
186 ModelGraphEditor
.prototype.removeNode = function (node
, success
, error
) {
187 console
.log('removeNode', JSON
.stringify(node
))
189 var current_layer
= self
.getCurrentView();
190 var node_type
= node
.info
.type
;
191 if (node
.info
.desc_id
== undefined) {
192 node
.info
.desc_id
= self
.desc_id
;
194 if (self
.model
.layer
[current_layer
] && self
.model
.layer
[current_layer
].nodes
[node_type
] && self
.model
.layer
[current_layer
].nodes
[node_type
].removable
) {
195 if (self
.model
.layer
[current_layer
].nodes
[node_type
].removable
.callback
) {
196 var c
= self
.model
.callback
[self
.model
.layer
[current_layer
].nodes
[node_type
].removable
.callback
].class;
197 var controller
= new TCD3
[c
]();
198 controller
[self
.model
.layer
[current_layer
].nodes
[node_type
].removable
.callback
](self
, node
, function () {
199 self
.parent
.removeNode
.call(self
, node
);
200 success
&& success();
204 log('removeNode: callback undefined in model spec.');
205 error
&& error("You can't remove a " + node
.info
.type
+ ", callback undefined.");
208 //FIXME we need to manage alert in a different way: FAILBACK
209 log("You can't remove a " + node
.info
.type
);
210 error
&& error("You can't remove a " + node
.info
.type
);
215 * Add a new link to graph.
216 * @param {Object} Required. An object that specifies tha data of the new Link.
219 ModelGraphEditor
.prototype.addLink = function (s
, d
, success
, error
) {
221 var source_id
= s
.id
;
222 var target_id
= d
.id
;
223 var source_type
= s
.info
.type
;
224 var destination_type
= d
.info
.type
;
228 view
: this.filter_parameters
.link
.view
[0],
229 group
: this.filter_parameters
.link
.group
,
230 desc_id
: this.desc_id
232 log("addLink: " + JSON
.stringify(link
))
233 var current_layer
= self
.getCurrentView()
234 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
]) {
236 if (self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].callback
) {
237 var callback
= self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].callback
;
238 console
.log(callback
, self
.model
.callback
)
239 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;
240 link
.directed_edge
= direct_edge
;
241 var c
= self
.model
.callback
[callback
].class;
242 var controller
= new TCD3
[c
]();
243 controller
[callback
](self
, link
, function () {
244 self
._deselectAllNodes();
245 self
.parent
.addLink
.call(self
, link
);
250 log('addLink: callback undefined in model spec.');
251 error
&& error("You can't add a link, callback undefined.");
255 //FIXME we need to manage alert in a different way: FAILBACK
256 log("You can't link a " + source_type
+ " with a " + destination_type
);
258 error
&& error("You can't link a " + source_type
+ " with a " + destination_type
);
263 * Remove a link from graph.
264 * @param {String} Required. The identifier of link to remove.
267 ModelGraphEditor
.prototype.removeLink = function (link
, success
, error
) {
271 var source_type
= s
.info
.type
;
272 var destination_type
= d
.info
.type
;
273 var current_layer
= self
.getCurrentView()
274 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
] &&
275 self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].removable
277 if (self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].removable
.callback
) {
278 var callback
= self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].removable
.callback
;
279 var c
= self
.model
.callback
[callback
].class;
280 var controller
= new TCD3
[c
]();
281 controller
[callback
](self
, link
, function () {
282 self
._deselectAllNodes();
283 self
._deselectAllLinks();
284 self
.parent
.removeLink
.call(self
, link
.index
);
285 success
&& success();
288 log('removeLink: callback undefined in model spec.');
289 error
&& error("You can't remove a link, callback undefined.");
293 //FIXME we need to manage alert in a different way: FAILBACK
294 log("You can't delete the link");
295 error
&& error("You can't delete the link");
302 ModelGraphEditor
.prototype.savePositions = function (data
) {
304 this.node
.each(function (d
) {
306 vertices
[d
.id
]['x'] = d
.x
;
307 vertices
[d
.id
]['y'] = d
.y
;
309 new TCD3
.GraphRequests().savePositions({
319 ModelGraphEditor
.prototype._setupBehaviorsOnEvents = function (layer
) {
322 var contextMenuLinksAction
= [{
323 title
: 'Delete Link',
324 action: function (elm
, link
, i
) {
325 self
.removeLink(link
, null, showAlert
);
329 var contextMenuNodesAction
= [{
331 action: function (elm
, d
, i
) {
332 if (d
.info
.type
!= undefined) {
333 self
.eventHandler
.fire("edit_descriptor", self
.project_id
, d
);
341 action: function (elm
, d
, i
) {
342 self
.removeNode(d
, null, showAlert
);
348 if (this.customBehavioursOnEvents
) {
349 contextMenuNodesAction
= contextMenuNodesAction
.concat(this.customBehavioursOnEvents
['behaviors'].nodes
);
353 if (self
.model
&& self
.model
.layer
&& self
.model
.layer
[layer
] && self
.model
.layer
[layer
].action
&& self
.model
.layer
[layer
].action
.node
) {
354 for (var i
in self
.model
.layer
[layer
].action
.node
) {
355 var action
= self
.model
.layer
[layer
].action
.node
[i
]
356 contextMenuNodesAction
.push({
358 action: function (elm
, d
, i
) {
359 var callback
= action
.callback
;
360 var c
= self
.model
.callback
[callback
].class;
361 var controller
= new TCD3
[c
]();
368 controller
[callback
](self
, args
);
370 edit_mode
: (action
.edit_mode
!== undefined) ? action
.edit_mode
: undefined
375 this.behavioursOnEvents
= {
377 'click': function (d
) {
379 d3
.event
.preventDefault();
381 if (self
._edit_mode
&& self
.lastKeyDown
=== SHIFT_BUTTON
&& self
._selected_node
!== undefined) {
382 self
.addLink(self
._selected_node
, d
, null, showAlert
);
384 self
._selectNodeExclusive(this, d
);
388 'mouseover': function (d
) {
389 self
.link
.style('stroke-width', function (l
) {
390 if (d
=== l
.source
|| d
=== l
.target
)
396 'mouseout': function (d
) {
397 self
.link
.style('stroke-width', 2);
399 'contextmenu': d3
.contextMenu(contextMenuNodesAction
, {
400 'edit_mode': self
._edit_mode
,
402 'type_object': 'node'
406 'click': function (d
) {
407 self
._selectLinkExclusive(this, d
);
410 'dblclick': function (event
) {
413 'mouseover': function (d
) {
414 d3
.select(this).style('stroke-width', 4);
416 'mouseout': function (d
) {
417 if (d
!== self
._selected_link
)
418 d3
.select(this).style('stroke-width', 2);
420 'contextmenu': d3
.contextMenu(contextMenuLinksAction
, {
421 'edit_mode': self
._edit_mode
,
423 'type_object': 'link'
429 ModelGraphEditor
.prototype.handleFiltersParams = function (filtersParams
, notFireEvent
) {
431 this.parent
.handleFiltersParams
.call(this, filtersParams
, notFireEvent
);
432 if (filtersParams
&& filtersParams
.link
&& filtersParams
.link
.view
)
433 this._setupBehaviorsOnEvents(filtersParams
.link
.view
[0]);
436 ModelGraphEditor
.prototype.getAvailableNodes = function () {
437 log('getAvailableNodes');
439 if (this.model
&& this.model
.layer
[this.getCurrentView()] !== undefined)
440 return this.model
.layer
[this.getCurrentView()].nodes
;
445 ModelGraphEditor
.prototype.getTypeProperty = function () {
446 return this.type_property
;
449 ModelGraphEditor
.prototype.getCurrentGroup = function () {
450 return this.filter_parameters
.node
.group
[0];
454 ModelGraphEditor
.prototype.getCurrentView = function () {
455 return this.filter_parameters
.link
.view
[0];
457 ModelGraphEditor
.prototype.getCurrentFilters = function () {
458 return this.filter_parameters
;
461 ModelGraphEditor
.prototype.getGraphParams = function () {
462 return this.d3_graph
.graph_parameters
;
470 console
.log("::ModelGraphEditor::", text
);
474 return ModelGraphEditor
;
479 if (typeof module
=== 'object') {
480 module
.exports
= TCD3
.ModelGraphEditor
;