fd80822dec01a0ccb6396f4fc8f43ef5651039f4
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
) {
184 var controller
= new TCD3
.OsmController();
185 controller
.updateNode(this,node
, args
, function(){
191 * Update the data properties of the node
192 * @param {Object} Required. An object that specifies tha data of the node.
195 ModelGraphEditor
.prototype.updateGraphParams = function (args
, success
, error
) {
196 var controller
= new TCD3
.OsmController();
197 controller
.updateGraphParams(args
, function(){
203 * Remove a node from graph and related links.
204 * @param {String} Required. Id of node to remove.
207 ModelGraphEditor
.prototype.removeNode = function (node
, success
, error
) {
208 console
.log('removeNode', JSON
.stringify(node
))
210 var current_layer
= self
.getCurrentView();
211 var node_type
= node
.info
.type
;
212 if (node
.info
.desc_id
== undefined) {
213 node
.info
.desc_id
= self
.desc_id
;
215 if (self
.model
.layer
[current_layer
] && self
.model
.layer
[current_layer
].nodes
[node_type
] && self
.model
.layer
[current_layer
].nodes
[node_type
].removable
) {
216 if (self
.model
.layer
[current_layer
].nodes
[node_type
].removable
.callback
) {
217 var c
= self
.model
.callback
[self
.model
.layer
[current_layer
].nodes
[node_type
].removable
.callback
].class;
218 var controller
= new TCD3
.OsmController();
219 controller
[self
.model
.layer
[current_layer
].nodes
[node_type
].removable
.callback
](self
, node
, function () {
220 self
.parent
.removeNode
.call(self
, node
);
221 success
&& success();
225 log('removeNode: callback undefined in model spec.');
226 error
&& error("You can't remove a " + node
.info
.type
+ ", callback undefined.");
229 //FIXME we need to manage alert in a different way: FAILBACK
230 log("You can't remove a " + node
.info
.type
);
231 error
&& error("You can't remove a " + node
.info
.type
);
236 * Add a new link to graph.
237 * @param {Object} Required. An object that specifies tha data of the new Link.
240 ModelGraphEditor
.prototype.addLink = function (s
, d
, success
, error
) {
242 var source_id
= s
.id
;
243 var target_id
= d
.id
;
244 var source_type
= s
.info
.type
;
245 var destination_type
= d
.info
.type
;
249 view
: this.filter_parameters
.link
.view
[0],
250 group
: this.filter_parameters
.link
.group
,
251 desc_id
: this.desc_id
253 log("addLink: " + JSON
.stringify(link
))
254 var current_layer
= self
.getCurrentView()
255 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
]) {
257 if (self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].callback
) {
258 var callback
= self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].callback
;
259 console
.log(callback
, self
.model
.callback
)
260 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;
261 link
.directed_edge
= direct_edge
;
262 var c
= self
.model
.callback
[callback
].class;
263 var controller
= new TCD3
.OsmController();
264 controller
[callback
](self
, link
, function () {
265 self
._deselectAllNodes();
266 self
.parent
.addLink
.call(self
, link
);
271 log('addLink: callback undefined in model spec.');
272 error
&& error("You can't add a link, callback undefined.");
276 //FIXME we need to manage alert in a different way: FAILBACK
277 log("You can't link a " + source_type
+ " with a " + destination_type
);
279 error
&& error("You can't link a " + source_type
+ " with a " + destination_type
);
284 * Remove a link from graph.
285 * @param {String} Required. The identifier of link to remove.
288 ModelGraphEditor
.prototype.removeLink = function (link
, success
, error
) {
292 var source_type
= s
.info
.type
;
293 var destination_type
= d
.info
.type
;
294 var current_layer
= self
.getCurrentView();
295 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
] &&
296 self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].removable
298 if (self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].removable
.callback
) {
299 var callback
= self
.model
.layer
[current_layer
].allowed_edges
[source_type
].destination
[destination_type
].removable
.callback
;
300 var c
= self
.model
.callback
[callback
].class;
301 var controller
= new TCD3
.OsmController();
302 controller
[callback
](self
, link
, function () {
303 self
._deselectAllNodes();
304 self
._deselectAllLinks();
305 self
.parent
.removeLink
.call(self
, link
.index
);
306 success
&& success();
309 log('removeLink: callback undefined in model spec.');
310 error
&& error("You can't remove a link, callback undefined.");
314 //FIXME we need to manage alert in a different way: FAILBACK
315 log("You can't delete the link");
316 error
&& error("You can't delete the link");
323 ModelGraphEditor
.prototype.savePositions = function (data
) {
325 this.node
.each(function (d
) {
327 vertices
[d
.id
]['x'] = d
.x
;
328 vertices
[d
.id
]['y'] = d
.y
;
330 new TCD3
.GraphRequests().savePositions({
340 ModelGraphEditor
.prototype._setupBehaviorsOnEvents = function (layer
) {
343 var contextMenuLinksAction
= [{
344 title
: 'Delete Link',
345 action: function (elm
, link
, i
) {
346 self
.removeLink(link
, null, showAlert
);
350 var contextMenuNodesAction
= [
353 action: function (elm
, d
, i
) {
354 self
.removeNode(d
, null, showAlert
);
360 if (this.customBehavioursOnEvents
) {
361 contextMenuNodesAction
= contextMenuNodesAction
.concat(this.customBehavioursOnEvents
['behaviors'].nodes
);
365 if (self
.model
&& self
.model
.layer
&& self
.model
.layer
[layer
] && self
.model
.layer
[layer
].action
&& self
.model
.layer
[layer
].action
.node
) {
366 for (var i
in self
.model
.layer
[layer
].action
.node
) {
367 var action
= self
.model
.layer
[layer
].action
.node
[i
]
368 contextMenuNodesAction
.push({
370 action: function (elm
, d
, i
) {
371 var callback
= action
.callback
;
372 var c
= self
.model
.callback
[callback
].class;
373 var controller
= new TCD3
[c
]();
380 controller
[callback
](self
, args
);
382 edit_mode
: (action
.edit_mode
!== undefined) ? action
.edit_mode
: undefined
387 this.behavioursOnEvents
= {
389 'click': function (d
) {
391 d3
.event
.preventDefault();
393 if (self
._edit_mode
&& self
.lastKeyDown
=== SHIFT_BUTTON
&& self
._selected_node
!== undefined) {
394 self
.addLink(self
._selected_node
, d
, null, showAlert
);
396 self
._selectNodeExclusive(this, d
);
400 'mouseover': function (d
) {
401 self
.link
.style('stroke-width', function (l
) {
402 if (d
=== l
.source
|| d
=== l
.target
)
408 'mouseout': function (d
) {
409 self
.link
.style('stroke-width', 2);
411 'contextmenu': d3
.contextMenu(contextMenuNodesAction
, {
412 'edit_mode': self
._edit_mode
,
414 'type_object': 'node'
418 'click': function (d
) {
419 self
._selectLinkExclusive(this, d
);
421 'dblclick': function (event
) {
424 'mouseover': function (d
) {
425 d3
.select(this).style('stroke-width', 4);
427 'mouseout': function (d
) {
428 if (d
!== self
._selected_link
)
429 d3
.select(this).style('stroke-width', 2);
431 'contextmenu': d3
.contextMenu(contextMenuLinksAction
, {
432 'edit_mode': self
._edit_mode
,
434 'type_object': 'link'
440 ModelGraphEditor
.prototype.handleFiltersParams = function (filtersParams
, notFireEvent
) {
442 this.parent
.handleFiltersParams
.call(this, filtersParams
, notFireEvent
);
443 if (filtersParams
&& filtersParams
.link
&& filtersParams
.link
.view
)
444 this._setupBehaviorsOnEvents(filtersParams
.link
.view
[0]);
447 ModelGraphEditor
.prototype.getAvailableNodes = function () {
448 log('getAvailableNodes');
450 if (this.model
&& this.model
.layer
[this.getCurrentView()] !== undefined)
451 return this.model
.layer
[this.getCurrentView()].nodes
;
456 ModelGraphEditor
.prototype.getTypeProperty = function () {
457 return this.type_property
;
460 ModelGraphEditor
.prototype.getCurrentGroup = function () {
461 return this.filter_parameters
.node
.group
[0];
464 ModelGraphEditor
.prototype.getCurrentView = function () {
465 return this.filter_parameters
.link
.view
[0];
467 ModelGraphEditor
.prototype.getCurrentFilters = function () {
468 return this.filter_parameters
;
471 ModelGraphEditor
.prototype.getGraphParams = function () {
472 return this.d3_graph
.graph_parameters
;
480 console
.log("::ModelGraphEditor::", text
);
484 return ModelGraphEditor
;
489 if (typeof module
=== 'object') {
490 module
.exports
= TCD3
.ModelGraphEditor
;