3308 lines
81 KiB
JavaScript
3308 lines
81 KiB
JavaScript
// Pandora FMS - http://pandorafms.com
|
|
// ==================================================
|
|
// Copyright (c) 2005-2010 Artica Soluciones Tecnologicas
|
|
// Please see http://pandorafms.org for full contribution list
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public License
|
|
// as published by the Free Software Foundation; version 2
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
/*-----------------------------------------------*/
|
|
/*-------------------Constants-------------------*/
|
|
/*-----------------------------------------------*/
|
|
var MAX_ZOOM_LEVEL = 50;
|
|
var RELATION_MINIMAP = 4;
|
|
var CONTROL_KEY = 17;
|
|
|
|
/*-----------------------------------------------*/
|
|
/*------------------Constructor------------------*/
|
|
/*-----------------------------------------------*/
|
|
var MapController = function(target, refresh_time) {
|
|
this._target = target;
|
|
this._refresh_time = refresh_time * 1000; // 1000 for the javascript
|
|
|
|
this._id = $(target).data('id');
|
|
}
|
|
|
|
/*-----------------------------------------------*/
|
|
/*------------------Atributes--------------------*/
|
|
/*-----------------------------------------------*/
|
|
MapController.prototype._id = null;
|
|
MapController.prototype._viewport = null;
|
|
MapController.prototype._viewport_nodes = null;
|
|
MapController.prototype._viewport_edges = null;
|
|
MapController.prototype._minimap_viewport = null;
|
|
MapController.prototype._minimap = null;
|
|
MapController.prototype._zoomManager = null;
|
|
MapController.prototype._slider = null;
|
|
MapController.prototype._relation = null;
|
|
MapController.prototype._dragging = false;
|
|
MapController.prototype._start_flag_multiple_selection = false;
|
|
MapController.prototype._flag_multiple_selection = false;
|
|
MapController.prototype._cache_files = {};
|
|
MapController.prototype._last_event = null;
|
|
MapController.prototype._keys_pressed = [];
|
|
MapController.prototype._last_mouse_position = null;
|
|
MapController.prototype._relationship_in_progress = false;
|
|
MapController.prototype._relationship_in_progress_type = null;
|
|
MapController.prototype._over = null
|
|
MapController.prototype._dragged_nodes = {};
|
|
MapController.prototype._enabled_minimap = true;
|
|
|
|
/*-----------------------------------------------*/
|
|
/*--------------------Methods--------------------*/
|
|
/*-----------------------------------------------*/
|
|
/**
|
|
* Function init_map
|
|
* Return void
|
|
* This function init the map
|
|
*/
|
|
MapController.prototype.init_map = function() {
|
|
var self = this;
|
|
|
|
width_svg = $("#map_" + self._id).width();
|
|
if ($("#main").height()) {
|
|
height_svg = $("#main").height();
|
|
}
|
|
else {
|
|
//Set the height in the pure view (fullscreen).
|
|
|
|
height_svg = $(window).height() -
|
|
$("#menu_tab_frame_view").height() -
|
|
20; // 20 of margin
|
|
}
|
|
|
|
var svg = d3.select(self._target + " svg");
|
|
|
|
svg
|
|
.attr("width", width_svg)
|
|
.attr("height", height_svg)
|
|
|
|
self._zoomManager =
|
|
d3.behavior.zoom()
|
|
.scaleExtent([1/MAX_ZOOM_LEVEL, MAX_ZOOM_LEVEL]).on("zoom", zoom);
|
|
|
|
self._viewport = svg
|
|
.call(self._zoomManager)
|
|
.append("g")
|
|
.attr("class", "viewport");
|
|
|
|
self._viewport_edges = self._viewport.append("g")
|
|
.attr("class", "viewport_edges");
|
|
|
|
self._viewport_nodes = self._viewport.append("g")
|
|
.attr("class", "viewport_nodes");
|
|
|
|
self._minimap = svg
|
|
.append("g")
|
|
.attr("class", "minimap");
|
|
|
|
/**
|
|
* Function zoom
|
|
* Return void
|
|
* This function manages the zoom
|
|
*/
|
|
function zoom() {
|
|
self.close_all_tooltips();
|
|
self.remove_resize_square();
|
|
|
|
if (!self._flag_multiple_selection) {
|
|
|
|
self.last_event = "zoom";
|
|
|
|
var zoom_level = d3.event.scale;
|
|
|
|
self._slider.property("value", Math.log(zoom_level));
|
|
|
|
self._viewport
|
|
.attr("transform",
|
|
"translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")");
|
|
|
|
self.zoom_minimap();
|
|
|
|
|
|
}
|
|
else {
|
|
self.last_event = null;
|
|
|
|
// Reset the zoom and panning actual
|
|
var viewport_transform = d3.transform(
|
|
d3.select(self._target + " .viewport").attr("transform"));
|
|
|
|
|
|
self._zoomManager
|
|
.scale(viewport_transform.scale[0])
|
|
.translate(viewport_transform.translate);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function zoom_in
|
|
* Return void
|
|
* This function zoom with "+" button
|
|
*/
|
|
function zoom_in(d) {
|
|
var step = parseFloat(self._slider.property("step"));
|
|
var slider_value = parseFloat(self._slider.property("value"));
|
|
|
|
slider_value += step;
|
|
|
|
var zoom_level = Math.exp(slider_value);
|
|
|
|
self._slider.property("value", Math.log(zoom_level));
|
|
self._slider.on("input")();
|
|
}
|
|
|
|
/**
|
|
* Function zoom_out
|
|
* Return void
|
|
* This function zoom with "-" button
|
|
*/
|
|
function zoom_out(d) {
|
|
var step = parseFloat(self._slider.property("step"));
|
|
var slider_value = parseFloat(self._slider.property("value"));
|
|
|
|
slider_value -= step;
|
|
|
|
var zoom_level = Math.exp(slider_value);
|
|
|
|
self._slider.property("value", Math.log(zoom_level));
|
|
self._slider.on("input")();
|
|
}
|
|
|
|
/**
|
|
* Function home_zoom
|
|
* Return void
|
|
* This function zoom with "H" button (reset zoom)
|
|
*/
|
|
function home_zoom(d) {
|
|
self._zoomManager.scale(1).translate([0, 0]).event(self._viewport);
|
|
}
|
|
|
|
/**
|
|
* Function slided
|
|
* Return void
|
|
* This function manages the slide (zoom system)
|
|
*/
|
|
function slided(d) {
|
|
var slider_value = parseFloat(self._slider.property("value"))
|
|
|
|
var zoom_level = Math.exp(slider_value);
|
|
|
|
/*----------------------------------------------------------------*/
|
|
/*-Code to translate the map with the zoom for to hold the center-*/
|
|
/*----------------------------------------------------------------*/
|
|
var center = [
|
|
parseFloat(d3.select(self._target).style('width')) / 2,
|
|
parseFloat(d3.select(self._target).style('height')) / 2];
|
|
|
|
var old_translate = self._zoomManager.translate();
|
|
var old_scale = self._zoomManager.scale();
|
|
|
|
var temp1 = [(center[0] - old_translate[0]) / old_scale,
|
|
(center[1] - old_translate[1]) / old_scale];
|
|
|
|
var temp2 = [temp1[0] * zoom_level + old_translate[0],
|
|
temp1[1] * zoom_level + old_translate[1]];
|
|
|
|
var new_translation = [
|
|
old_translate[0] + center[0] - temp2[0],
|
|
old_translate[1] + center[1] - temp2[1]];
|
|
|
|
self._zoomManager.scale(zoom_level)
|
|
.translate(new_translation)
|
|
.event(self._viewport);
|
|
}
|
|
|
|
self._slider = d3.select(self._target + " .zoom_controller .vertical_range")
|
|
.property("value", 0)
|
|
.property("min", -Math.log(MAX_ZOOM_LEVEL))
|
|
.property("max", Math.log(MAX_ZOOM_LEVEL))
|
|
.property("step", Math.log(MAX_ZOOM_LEVEL) * 2 / MAX_ZOOM_LEVEL)
|
|
.on("input", slided);
|
|
|
|
d3.select(self._target + " .zoom_box .home_zoom")
|
|
.on("click", home_zoom);
|
|
|
|
d3.select(self._target + " .zoom_box .zoom_in")
|
|
.on("click", zoom_in);
|
|
|
|
d3.select(self._target + " .zoom_box .zoom_out")
|
|
.on("click", zoom_out);
|
|
|
|
self.paint_nodes();
|
|
self.paint_arrows();
|
|
|
|
|
|
if (self._enabled_minimap)
|
|
self.init_minimap();
|
|
|
|
self.ini_selection_rectangle();
|
|
|
|
self.events();
|
|
}
|
|
|
|
MapController.prototype.set_nodes_map = function(nodes) {
|
|
var self = this;
|
|
|
|
window["nodes_" + self._id] = nodes;
|
|
}
|
|
|
|
MapController.prototype.get_nodes_map = function() {
|
|
var self = this;
|
|
|
|
return window["nodes_" + self._id];
|
|
}
|
|
|
|
MapController.prototype.get_edges_map = function() {
|
|
var self = this;
|
|
|
|
return window["edges_" + self._id];
|
|
}
|
|
|
|
MapController.prototype.set_edges_map = function(edges) {
|
|
var self = this;
|
|
|
|
window["edges_" + self._id] = edges;
|
|
}
|
|
|
|
MapController.prototype.get_subtype_map = function() {
|
|
var self = this;
|
|
|
|
return window["subtype_" + self._id];
|
|
}
|
|
|
|
MapController.prototype.get_filter_map = function() {
|
|
var self = this;
|
|
|
|
return window["filter_" + self._id];
|
|
}
|
|
|
|
/**
|
|
* Function ini_selection_rectangle
|
|
* Return void
|
|
* This function init the rectangle selection
|
|
*/
|
|
MapController.prototype.ini_selection_rectangle = function() {
|
|
var self = this;
|
|
|
|
d3.select(self._target + " svg")
|
|
.append("g")
|
|
.attr("id", "layer_selection_rectangle");
|
|
}
|
|
|
|
/**
|
|
* Function minimap_get_size
|
|
* Return [width, height]
|
|
* This function returns the minimap size
|
|
*/
|
|
MapController.prototype.minimap_get_size = function() {
|
|
var self = this;
|
|
|
|
var minimap_size = [];
|
|
minimap_size[0] = d3.selectAll(self._target + " .minimap rect").attr("width");
|
|
minimap_size[1] = d3.selectAll(self._target + " .minimap rect").attr("height");
|
|
|
|
return minimap_size;
|
|
}
|
|
|
|
/**
|
|
* Function get_node
|
|
* Return node
|
|
* This function returns a node
|
|
*/
|
|
MapController.prototype.get_node = function(id_graph) {
|
|
var self = this;
|
|
var return_node = null;
|
|
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (node['graph_id'] == id_graph) {
|
|
|
|
node['index_node'] = i;
|
|
|
|
return_node = node;
|
|
|
|
return false;
|
|
}
|
|
});
|
|
|
|
return return_node;
|
|
}
|
|
|
|
/**
|
|
* Function get_node_filter
|
|
* Return void
|
|
* This function returns the node filter
|
|
*/
|
|
MapController.prototype.get_node_filter = function(field, value) {
|
|
var self = this;
|
|
|
|
var return_node = null;
|
|
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (node[field] == value) {
|
|
return_node = node;
|
|
return false;
|
|
}
|
|
});
|
|
|
|
return return_node;
|
|
}
|
|
|
|
/**
|
|
* Function get_node_type
|
|
* Return node type
|
|
* This function returns a node type (module, agent or edge)
|
|
*/
|
|
MapController.prototype.get_node_type = function(id_graph) {
|
|
var self = this;
|
|
|
|
var node = self.get_node(id_graph);
|
|
|
|
if (node !== null) {
|
|
return node['type'];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Function get_edges_from_node
|
|
* Return array[edge]
|
|
* This function returns the edges of a node
|
|
*/
|
|
MapController.prototype.get_edges_from_node = function(id_graph) {
|
|
var self = this;
|
|
|
|
var return_edges = [];
|
|
|
|
$.each(self.get_edges_map(), function(i, edge) {
|
|
if ((edge['to'] == id_graph) || (edge['from'] == id_graph)) {
|
|
return_edges.push(edge);
|
|
}
|
|
});
|
|
|
|
return return_edges;
|
|
}
|
|
|
|
/**
|
|
* Function update_edges_from_clean_arrows
|
|
* Return void
|
|
* This function updates the graph id of the edges
|
|
*/
|
|
MapController.prototype.update_edges_from_clean_arrows = function(clean_arrows) {
|
|
var self = this;
|
|
|
|
newEdges = [];
|
|
clean_arrows.forEach(function(arrow, index) {
|
|
newEdges[index] = arrow;
|
|
});
|
|
|
|
self.set_edges_map(newEdges);
|
|
}
|
|
|
|
/**
|
|
* Function get_arrow_from_id
|
|
* Return void
|
|
* This function return an arrow from a specific id
|
|
*/
|
|
MapController.prototype.get_arrow_from_id = function(id) {
|
|
var self = this;
|
|
|
|
var arrow = $.grep(self.get_edges_map(), function(e) {
|
|
if (e['graph_id'] == id) {
|
|
return true;
|
|
}
|
|
});
|
|
|
|
|
|
if (arrow.length == 0) {
|
|
return null;
|
|
}
|
|
else {
|
|
return arrow[0];
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Function get_arrows_from_edges
|
|
* Return array[]
|
|
* This function returns a collection of arrows from edges (array)
|
|
*/
|
|
MapController.prototype.get_arrows_from_edges = function() {
|
|
var self = this;
|
|
|
|
var return_var = [];
|
|
|
|
$.each(self.get_edges_map(), function(i, e) {
|
|
return_var.push(self.get_arrow_from_id(e['graph_id']));
|
|
});
|
|
|
|
return return_var;
|
|
}
|
|
|
|
/**
|
|
* Function get_arrow
|
|
* Return void
|
|
* This function return a specific arrow
|
|
*/
|
|
MapController.prototype.get_arrow = function(id_to, id_from) {
|
|
var self = this;
|
|
var arrow = {};
|
|
|
|
arrow['nodes'] = {};
|
|
|
|
var count_nodes = 0;
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (parseInt(node['graph_id']) == parseInt(id_to)) {
|
|
arrow['nodes']['to'] = node;
|
|
count_nodes++;
|
|
}
|
|
else if (parseInt(node['graph_id']) == parseInt(id_from)) {
|
|
arrow['nodes']['from'] = node;
|
|
count_nodes++;
|
|
}
|
|
});
|
|
|
|
if (count_nodes == 2) {
|
|
$.each(self.get_edges_map(), function(i, edge) {
|
|
if (edge['to'] == arrow['nodes']['to']['graph_id'] &&
|
|
edge['from'] == arrow['nodes']['from']['graph_id']) {
|
|
|
|
arrow['arrow'] = edge;
|
|
|
|
return false; // Break
|
|
}
|
|
});
|
|
|
|
return arrow;
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function paint_toggle_button
|
|
* Return void
|
|
* This function paints the hide/show button (minimap)
|
|
*/
|
|
MapController.prototype.paint_toggle_button = function(wait) {
|
|
var self = this;
|
|
|
|
if (typeof(wait) === "undefined")
|
|
wait = 1;
|
|
|
|
var count_files = 2;
|
|
function wait_load(callback) {
|
|
count_files--;
|
|
|
|
if (count_files == 0) {
|
|
callback();
|
|
}
|
|
}
|
|
|
|
var map = d3.select(self._target + " svg");
|
|
var minimap = d3.select(self._target + " .minimap");
|
|
|
|
var transform = d3.transform();
|
|
|
|
var minimap_transform = d3.transform(minimap.attr("transform"));
|
|
|
|
switch (wait) {
|
|
case 1:
|
|
var toggle_minimap_button_layer = map.append("g")
|
|
.attr("id", "toggle_minimap_button");
|
|
|
|
if (is_buggy_firefox) {
|
|
toggle_minimap_button_layer.append("g")
|
|
.attr("class", "toggle_minimap_on")
|
|
.append("use")
|
|
.attr("xlink:href", "#toggle_minimap_on");
|
|
|
|
arrow_layout.append("g")
|
|
.attr("class", "toggle_minimap_off")
|
|
.style("opacity", 0)
|
|
.append("use")
|
|
.attr("xlink:href", "#toggle_minimap_off");
|
|
|
|
self.paint_toggle_button(0);
|
|
}
|
|
else {
|
|
toggle_minimap_button_layer.append("g")
|
|
.attr("class", "toggle_minimap_on")
|
|
.append("use")
|
|
.attr("xlink:href", "images/maps/toggle_minimap_on.svg#toggle_minimap_on")
|
|
.on("load", function() {
|
|
wait_load(function() {
|
|
self.paint_toggle_button(0);
|
|
});
|
|
});
|
|
|
|
toggle_minimap_button_layer.append("g")
|
|
.attr("class", "toggle_minimap_off")
|
|
.style("opacity", 0)
|
|
.append("use")
|
|
.attr("xlink:href", "images/maps/toggle_minimap_off.svg#toggle_minimap_off")
|
|
.on("load", function() {
|
|
wait_load(function() {
|
|
self.paint_toggle_button(0);
|
|
});
|
|
});
|
|
}
|
|
break;
|
|
case 0:
|
|
var toggle_minimap_button_layer =
|
|
d3.select(self._target + " #toggle_minimap_button");
|
|
|
|
var toggle_minimap_button_layer_bbox =
|
|
toggle_minimap_button_layer.node().getBBox();
|
|
|
|
transform.translate[0] = minimap_transform.translate[0];
|
|
transform.translate[1] = self.minimap_get_size()[1]
|
|
- toggle_minimap_button_layer_bbox.height;
|
|
|
|
toggle_minimap_button_layer.attr("transform", transform.toString());
|
|
|
|
toggle_minimap_button_layer.on("click",
|
|
function() {
|
|
self.event_toggle_minimap();
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function event_toggle_minimap
|
|
* Return void
|
|
* This function captures the minimap events
|
|
*/
|
|
MapController.prototype.event_toggle_minimap = function() {
|
|
var self = this;
|
|
|
|
var map_size = d3.select(self._target).node().getBoundingClientRect();
|
|
|
|
var toggle_minimap_on = parseInt(d3
|
|
.select(self._target + " .toggle_minimap_on").style("opacity"));
|
|
|
|
var toggle_minimap_button_layer =
|
|
d3.select(self._target + " #toggle_minimap_button");
|
|
|
|
var transform_toggle_minimap_button = d3
|
|
.transform(toggle_minimap_button_layer.attr("transform"));
|
|
|
|
var toggle_minimap_button_layer_bbox =
|
|
toggle_minimap_button_layer.node().getBBox();
|
|
|
|
|
|
var minimap = d3.select(self._target + " .minimap");
|
|
var minimap_transform = d3.transform(minimap.attr("transform"));
|
|
|
|
switch (toggle_minimap_on) {
|
|
case 0:
|
|
transform_toggle_minimap_button
|
|
.translate[0] = minimap_transform.translate[0];
|
|
transform_toggle_minimap_button
|
|
.translate[1] = self.minimap_get_size()[1] - toggle_minimap_button_layer_bbox.height;
|
|
|
|
toggle_minimap_button_layer.attr("transform",
|
|
transform_toggle_minimap_button);
|
|
|
|
|
|
d3.select(self._target + " .minimap")
|
|
.style("opacity", 1);
|
|
|
|
d3.select(self._target + " .toggle_minimap_off")
|
|
.style("opacity", 0);
|
|
d3.select(self._target + " .toggle_minimap_on")
|
|
.style("opacity", 1);
|
|
break;
|
|
case 1:
|
|
transform_toggle_minimap_button.translate[0] =
|
|
map_size.width - toggle_minimap_button_layer_bbox.width;
|
|
transform_toggle_minimap_button.translate[1] = 0;
|
|
|
|
toggle_minimap_button_layer.attr("transform",
|
|
transform_toggle_minimap_button);
|
|
|
|
|
|
d3.select(self._target + " .minimap")
|
|
.style("opacity", 0);
|
|
|
|
d3.select(self._target + " .toggle_minimap_off")
|
|
.style("opacity", 1);
|
|
d3.select(self._target + " .toggle_minimap_on")
|
|
.style("opacity", 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function get_real_size_map
|
|
* Return [width, height]
|
|
* This function returns the real map size
|
|
*/
|
|
MapController.prototype.get_real_size_map = function() {
|
|
var self = this;
|
|
|
|
var map_size = d3.select(self._target + " .viewport").node().getBBox();
|
|
|
|
if (map_size.width == 0) {
|
|
map_size.width = 100;
|
|
}
|
|
if (map_size.height == 0) {
|
|
map_size.height = 100;
|
|
}
|
|
|
|
return map_size;
|
|
}
|
|
|
|
MapController.prototype.init_minimap = function() {
|
|
var self = this;
|
|
|
|
var map_size = self.get_real_size_map();
|
|
|
|
var real_width = map_size.width + map_size.x;
|
|
var real_height = map_size.height + map_size.y;
|
|
|
|
self.paint_minimap(real_width, real_height);
|
|
|
|
|
|
|
|
self.paint_toggle_button();
|
|
|
|
self.paint_items_minimap();
|
|
|
|
self.zoom_minimap();
|
|
|
|
self.events_for_minimap();
|
|
}
|
|
|
|
/**
|
|
* Function paint_minimap
|
|
* Return void
|
|
* This function paints the minimap
|
|
*/
|
|
MapController.prototype.paint_minimap = function(map_width, map_height) {
|
|
var self = this;
|
|
|
|
var screen_size = d3.select(self._target).node().getBoundingClientRect();
|
|
|
|
var max_map = map_height;
|
|
if (map_width > map_height)
|
|
max_map = map_width;
|
|
|
|
var max_screen = screen_size.height;
|
|
if (screen_size.width > screen_size.height)
|
|
max_screen = screen_size.width;
|
|
|
|
self._relation = RELATION_MINIMAP * max_map / max_screen;
|
|
if (self._relation < 1)
|
|
self._relation = 1;
|
|
|
|
|
|
var minimap_map_width = map_width / self._relation;
|
|
var minimap_map_height = map_height / self._relation;
|
|
|
|
var minimap = d3.select(self._target + " .minimap");
|
|
var svg = d3.select(self._target + " svg");
|
|
|
|
var transform = d3.transform();
|
|
|
|
// Move the minimap to the right upper corner
|
|
transform.translate[0] = screen_size.width - minimap_map_width;
|
|
transform.translate[1] = 0;
|
|
minimap.attr("transform", transform.toString());
|
|
|
|
svg.append("defs")
|
|
.append("clipPath")
|
|
.attr("id", "clip_minimap")
|
|
.append("rect")
|
|
.attr("x", 0)
|
|
.attr("y", 0)
|
|
.attr("width", minimap_map_width)
|
|
.attr("height", minimap_map_height);
|
|
|
|
minimap
|
|
.append("rect")
|
|
.attr("x", 0)
|
|
.attr("y", 0)
|
|
.attr("width", minimap_map_width)
|
|
.attr("height", minimap_map_height)
|
|
.attr("style", "fill: #ffffff; stroke: #000000; stroke-width: 1;");
|
|
|
|
transform = d3.transform();
|
|
transform.scale[0] = 1 / self._relation;
|
|
transform.scale[1] = 1 / self._relation;
|
|
|
|
self._minimap_viewport = minimap
|
|
.append("g")
|
|
.attr("class", "clip_minimap")
|
|
.attr("clip-path", "url(#clip_minimap)")
|
|
.append("g")
|
|
.attr("class", "map")
|
|
.attr("transform", transform.toString());
|
|
|
|
self._minimap_viewport.append("rect")
|
|
.attr("class", "viewport")
|
|
.attr("style", "fill: #dddddd; stroke: #aaaaaa; stroke-width: 1;")
|
|
.attr("x", 0)
|
|
.attr("y", 0)
|
|
.attr("height", screen_size.height)
|
|
.attr("width", screen_size.width);
|
|
}
|
|
|
|
/**
|
|
* Function paint_items_minimap
|
|
* Return void
|
|
* This function paints the minimap items
|
|
*/
|
|
MapController.prototype.paint_items_minimap = function() {
|
|
var self = this;
|
|
|
|
self._minimap_viewport.selectAll(".node")
|
|
.data(
|
|
self.get_nodes_map()
|
|
.filter(function(d, i) {
|
|
return self.filter_only_agents(d);
|
|
}))
|
|
.enter()
|
|
.append("g")
|
|
.attr("transform",
|
|
function(d) {
|
|
var x = d['x'];
|
|
var y = d['y'];
|
|
|
|
return "translate(" + x + " " + y + ")";
|
|
})
|
|
.attr("class", "node")
|
|
.attr("id", function(d) { return "node_" + d['graph_id'];})
|
|
.attr("data-id", function(d) { return d['id'];})
|
|
.attr("data-graph_id", function(d) { return d['graph_id'];})
|
|
.attr("data-type", function(d) { return d['type'];})
|
|
.append("circle")
|
|
.attr("style", "fill: rgb(50, 50, 128);")
|
|
.attr("x", 0)
|
|
.attr("y", 0)
|
|
.attr("r", 30);
|
|
}
|
|
|
|
/**
|
|
* Function zoom_minimap
|
|
* Return void
|
|
* This function apply zoom in minimap
|
|
*/
|
|
MapController.prototype.zoom_minimap = function() {
|
|
var self = this;
|
|
|
|
var viewport_transform = d3.transform(
|
|
d3.select(self._target + " .viewport").attr("transform"));
|
|
|
|
var transform = d3.transform();
|
|
|
|
var minimap_viewport = d3.select(self._target + " .minimap .viewport");
|
|
|
|
transform.translate[0] = -viewport_transform.translate[0];
|
|
transform.translate[1] = -viewport_transform.translate[1];
|
|
|
|
transform.scale[0] = 1 / viewport_transform.scale[0];
|
|
transform.scale[1] = 1 / viewport_transform.scale[1];
|
|
|
|
minimap_viewport
|
|
.attr("transform", transform.toString());
|
|
}
|
|
|
|
/**
|
|
* Function node_from_edge
|
|
* Return node
|
|
* This function returns the node with the specific id_graph
|
|
*/
|
|
MapController.prototype.node_from_edge = function(id_graph) {
|
|
var self = this;
|
|
|
|
var exists = null;
|
|
|
|
$.each(self.get_edges_map(), function(i, e) {
|
|
if (e.graph_id == id_graph) {
|
|
exists = i;
|
|
return false; // jquery.each break;
|
|
}
|
|
});
|
|
|
|
if (exists !== null)
|
|
return self.get_edges_map()[exists];
|
|
else
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Function exists_edge
|
|
* Return bool
|
|
* This function returns if the node exist
|
|
*/
|
|
MapController.prototype.exists_edge = function(id_graph) {
|
|
var self = this;
|
|
|
|
var exists = false;
|
|
|
|
$.each(self.get_edges_map(), function(i, e) {
|
|
if (e.graph_id == id_graph) {
|
|
exists = true;
|
|
return false; // jquery.each break;
|
|
}
|
|
});
|
|
|
|
return exists;
|
|
}
|
|
|
|
/**
|
|
* Function paint_arrows
|
|
* Return void
|
|
* This function paints the arrows
|
|
*/
|
|
MapController.prototype.paint_arrows = function() {
|
|
var self = this;
|
|
|
|
var arrow_layouts = self._viewport.selectAll(".arrow")
|
|
.data(
|
|
self.get_nodes_map()
|
|
.filter(function(d, i) {
|
|
if (d.type == ITEM_TYPE_EDGE_NETWORKMAP) {
|
|
if (self.exists_edge(d['graph_id']))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
else
|
|
return false;
|
|
}))
|
|
.enter()
|
|
.append("g")
|
|
.attr("class", "arrow")
|
|
.attr("id", function(d) { return "arrow_" + d['graph_id'];})
|
|
|
|
.attr("data-id", function(d) { return d['id'];})
|
|
.attr("data-to", function(d) {
|
|
return self.node_from_edge(d['graph_id'])["to"];})
|
|
.attr("data-from", function(d) {
|
|
return self.node_from_edge(d['graph_id'])["from"];});
|
|
|
|
create_arrow(arrow_layouts);
|
|
|
|
/**
|
|
* Function create_arrow
|
|
* Return void
|
|
* This function creates the arrow
|
|
*/
|
|
function create_arrow(arrow_layouts) {
|
|
|
|
arrow_layouts.each(function(d) {
|
|
var arrow_layout = this;
|
|
|
|
var node_arrow = self.get_edges_map().filter(function(d2) {
|
|
if (d2['graph_id'] == d['graph_id'])
|
|
return true;
|
|
else
|
|
return false;
|
|
})[0];
|
|
|
|
var to_node = self.get_nodes_map().filter(function(d2) {
|
|
if (d2['graph_id'] == node_arrow['to'])
|
|
return true;
|
|
else
|
|
return false;
|
|
})[0];
|
|
|
|
var from_node = self.get_nodes_map().filter(function(d2) {
|
|
if (d2['graph_id'] == node_arrow['from'])
|
|
return true;
|
|
else
|
|
return false;
|
|
})[0];
|
|
|
|
var id_arrow = d3.select(arrow_layout).attr("id");
|
|
var id_node_to = "node_" + to_node['graph_id'];
|
|
var id_node_from = "node_" + from_node['graph_id'];
|
|
|
|
|
|
self.arrow_by_pieces(self._target + " svg", id_arrow,
|
|
id_node_to, id_node_from);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function paint_nodes
|
|
* Return void
|
|
* This function paint the nodes
|
|
*/
|
|
MapController.prototype.paint_nodes = function() {
|
|
var self = this;
|
|
|
|
self._viewport.selectAll(".node")
|
|
.data(
|
|
self.get_nodes_map()
|
|
.filter(function(d, i) {
|
|
return self.filter_only_agents(d);
|
|
}))
|
|
.enter()
|
|
.append("g")
|
|
.attr("transform",
|
|
function(d) { return "translate(" + d['x'] + " " + d['y'] + ")";})
|
|
.attr("class", "draggable node")
|
|
.attr("id", function(d) { return "node_" + d['graph_id'];})
|
|
.attr("style", "fill: rgb(50, 50, 128);")
|
|
.attr("data-id", function(d) { return d['id'];})
|
|
.attr("data-graph_id", function(d) { return d['graph_id'];})
|
|
.attr("data-type", function(d) { return d['type'];})
|
|
.append("rect")
|
|
.attr("style", "")
|
|
.attr("x", 0)
|
|
.attr("y", 0)
|
|
.attr("height", 30)
|
|
.attr("width", 30);
|
|
}
|
|
|
|
/**
|
|
* Function move_arrow
|
|
* Return void
|
|
* This function moves the arrow
|
|
*/
|
|
MapController.prototype.move_arrow = function (id_from_any_point_arrow) {
|
|
var self = this;
|
|
|
|
var arrows = d3.selectAll(self._target + " .arrow").filter(function(d2) {
|
|
if (
|
|
(d3.select(this).attr("data-to") == id_from_any_point_arrow) ||
|
|
(d3.select(this).attr("data-from") == id_from_any_point_arrow)
|
|
) {
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
arrows.each(function(d) {
|
|
self.arrow_by_pieces(self._target + " svg", d, 0);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function remove_resize_square
|
|
* Return void
|
|
* This function removes squares resize
|
|
*/
|
|
MapController.prototype.remove_resize_square = function(item, wait) {
|
|
var self = this;
|
|
|
|
d3.select(self._target + " svg #resize_square").remove();
|
|
}
|
|
|
|
/**
|
|
* Function positioning_resize_square
|
|
* Return void
|
|
* This function positioning the square to resize the element
|
|
*/
|
|
MapController.prototype.positioning_resize_square = function(item) {
|
|
var self = this;
|
|
|
|
var resize_square = d3.select(self._target + " #resize_square");
|
|
var item_d3 = d3.select(self._target + " #node_" + item['graph_id']);
|
|
|
|
var bbox_item = item_d3.node().getBBox();
|
|
var bbox_square = resize_square.node().getBBox();
|
|
var transform_item = d3.transform(item_d3.attr("transform"));
|
|
var transform_viewport = d3
|
|
.transform(d3.select(self._target + " .viewport").attr("transform"));
|
|
|
|
var transform = d3.transform();
|
|
|
|
var x = (bbox_item.x +
|
|
transform_item.translate[0] +
|
|
transform_viewport.translate[0]
|
|
) * transform_viewport.scale[0];
|
|
var y = (bbox_item.y +
|
|
transform_item.translate[1] +
|
|
transform_viewport.translate[1]
|
|
) * transform_viewport.scale[1];
|
|
|
|
x = (bbox_item.x +
|
|
transform_item.translate[0]) * transform_viewport.scale[0] +
|
|
transform_viewport.translate[0];
|
|
y = (bbox_item.y +
|
|
transform_item.translate[1]) * transform_viewport.scale[1] +
|
|
transform_viewport.translate[1];
|
|
|
|
transform.translate[0] = x;
|
|
transform.translate[1] = y;
|
|
|
|
resize_square
|
|
.attr("transform", transform.toString());
|
|
|
|
var real_item_width = (bbox_item.width * transform_item.scale[0]);
|
|
var real_item_height = (bbox_item.height * transform_item.scale[1]);
|
|
|
|
d3.select("#resize_square .square rect")
|
|
.attr("width",
|
|
(real_item_width * transform_viewport.scale[0]));
|
|
d3.select("#resize_square .square rect")
|
|
.attr("height",
|
|
(real_item_height * transform_viewport.scale[1]));
|
|
|
|
// Set the handlers
|
|
var bbox_handler = d3
|
|
.select(self._target + " .handler").node().getBBox();
|
|
|
|
var handler_positions = {};
|
|
handler_positions['N'] = [];
|
|
handler_positions['N'][0] = (real_item_width * transform_viewport.scale[0] / 2)
|
|
- (bbox_handler.width / 2);
|
|
handler_positions['N'][1] = 0 - (bbox_handler.height / 2);
|
|
|
|
handler_positions['NE'] = [];
|
|
handler_positions['NE'][0] = (real_item_width * transform_viewport.scale[0])
|
|
- (bbox_handler.width / 2);
|
|
handler_positions['NE'][1] = handler_positions['N'][1];
|
|
|
|
handler_positions['E'] = [];
|
|
handler_positions['E'][0] = handler_positions['NE'][0];
|
|
handler_positions['E'][1] = (real_item_height * transform_viewport.scale[1] / 2)
|
|
- (bbox_handler.height / 2);
|
|
|
|
handler_positions['SE'] = [];
|
|
handler_positions['SE'][0] = handler_positions['NE'][0];
|
|
handler_positions['SE'][1] = (real_item_height * transform_viewport.scale[1])
|
|
- (bbox_handler.height / 2);
|
|
|
|
handler_positions['S'] = [];
|
|
handler_positions['S'][0] = handler_positions['N'][0];
|
|
handler_positions['S'][1] = handler_positions['SE'][1];
|
|
|
|
handler_positions['SW'] = [];
|
|
handler_positions['SW'][0] = 0 - (bbox_handler.width / 2);
|
|
handler_positions['SW'][1] = handler_positions['SE'][1];
|
|
|
|
handler_positions['W'] = [];
|
|
handler_positions['W'][0] = handler_positions['SW'][0];
|
|
handler_positions['W'][1] = handler_positions['E'][1];
|
|
|
|
handler_positions['NW'] = [];
|
|
handler_positions['NW'][0] = handler_positions['SW'][0];
|
|
handler_positions['NW'][1] = handler_positions['N'][1];
|
|
|
|
d3.selectAll(" .handler").each(function(d) {
|
|
var transform = d3.transform();
|
|
|
|
transform.translate[0] = handler_positions[d][0];
|
|
transform.translate[1] = handler_positions[d][1];
|
|
|
|
d3.select(self._target + " .handler_" + d)
|
|
.attr("transform", transform.toString());
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function paint_resize_square
|
|
* Return void
|
|
* This function paints a square to resize the elements
|
|
*/
|
|
MapController.prototype.paint_resize_square = function(item, wait) {
|
|
var self = this;
|
|
|
|
if (typeof(wait) === "undefined")
|
|
wait = 1;
|
|
|
|
var count_files = 16;
|
|
function wait_load(callback) {
|
|
count_files--;
|
|
|
|
if (count_files == 0) {
|
|
callback();
|
|
}
|
|
}
|
|
|
|
switch (wait) {
|
|
/*---------------------------------------------------*/
|
|
/*--------------- Prepare the square ----------------*/
|
|
/*---------------------------------------------------*/
|
|
case 1:
|
|
var resize_square = d3
|
|
.select(self._target + " svg")
|
|
.append("g").attr("id", "resize_square")
|
|
.style("opacity", 0);
|
|
|
|
d3.xml("images/maps/square_selection.svg", "application/xml", function(xml) {
|
|
var nodes = xml
|
|
.evaluate("//*[@id='square_selection']/*", xml, null, XPathResult.ANY_TYPE, null);
|
|
var result = nodes.iterateNext();
|
|
|
|
resize_square
|
|
.append("g").attr("class", "square_selection")
|
|
.append(function() {return result});
|
|
|
|
if (is_buggy_firefox) {
|
|
resize_square
|
|
.append("g").attr("class", "handles")
|
|
.selectAll(".handle")
|
|
.data(["N", "NE", "E", "SE", "S", "SW", "W", "NW"])
|
|
.enter()
|
|
.append("g")
|
|
.attr("class", function(d) { return "handler handler_" + d;})
|
|
.append("use")
|
|
.attr("xlink:href", "images/maps/resize_handle.svg#resize_handle")
|
|
.attr("class", function(d) { return "handler " + d;});
|
|
|
|
self.paint_resize_square(item, 0);
|
|
}
|
|
else {
|
|
var handles = resize_square
|
|
.append("g").attr("class", "handles");
|
|
|
|
handles.selectAll(".handle")
|
|
.data(["N", "NE", "E", "SE", "S", "SW", "W", "NW"])
|
|
.enter()
|
|
.append("g")
|
|
.attr("class", function(d) { return "handler handler_" + d;});
|
|
|
|
handles.selectAll(".handler").each(function(d) {
|
|
d3.select(this)
|
|
.append("use")
|
|
.style("opacity", 1)
|
|
.attr("class", "default")
|
|
.attr("xlink:href", "images/maps/resize_handle.svg#resize_handle")
|
|
.on("load", function() {
|
|
wait_load(function() {
|
|
self.paint_resize_square(
|
|
item, 0);
|
|
});
|
|
});
|
|
|
|
d3.select(this)
|
|
.append("use")
|
|
.style("opacity", 0)
|
|
.attr("class", "over")
|
|
.attr("xlink:href", "images/maps/resize_handle.over.svg#resize_handle_over")
|
|
.on("load", function() {
|
|
wait_load(function() {
|
|
self.paint_resize_square(
|
|
item, 0);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
});
|
|
break;
|
|
/*---------------------------------------------------*/
|
|
/*-------- Paint and positioning the square ---------*/
|
|
/*---------------------------------------------------*/
|
|
case 0:
|
|
self.positioning_resize_square(item);
|
|
|
|
d3.selectAll(" .handler").each(function(d) {
|
|
var drag = d3.behavior.drag()
|
|
.origin(function(d) { return d; })
|
|
.on("dragstart", function(d) {
|
|
self.event_resize("dragstart", item, d);
|
|
})
|
|
.on("drag", function(d) {
|
|
self.event_resize("drag", item, d);
|
|
})
|
|
.on("dragend", function(d) {
|
|
self.event_resize("dragend", item, d);
|
|
});
|
|
|
|
d3.select(this).call(drag);
|
|
|
|
d3.select(this)
|
|
.on("mouseover", function(d) {
|
|
self.change_handler_image("mouseover", d);
|
|
})
|
|
.on("mouseout", function(d) {
|
|
self.change_handler_image("mouseout", d);
|
|
});
|
|
});
|
|
|
|
var resize_square = d3.select(self._target + " #resize_square");
|
|
|
|
resize_square.style("opacity", 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function change_handler_image
|
|
* Return void
|
|
* This function changes the handler image
|
|
*/
|
|
MapController.prototype.change_handler_image = function(action, handler, wait) {
|
|
var self = this;
|
|
|
|
var handlers_d3 = d3.select(self._target + " .handles");
|
|
var handler_d3 = d3.select(self._target + " .handler_" + handler);
|
|
|
|
switch (action) {
|
|
case "mouseover":
|
|
handler_d3.select(".default").style("opacity", 0);
|
|
handler_d3.select(".over").style("opacity", 1);
|
|
break;
|
|
case "mouseout":
|
|
handler_d3.select(".default").style("opacity", 1);
|
|
handler_d3.select(".over").style("opacity", 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function event_resize
|
|
* Return void
|
|
* This function manages the resize event
|
|
*/
|
|
MapController.prototype.event_resize = function(action, item, handler) {
|
|
var self = this;
|
|
|
|
d3.event.sourceEvent.stopPropagation();
|
|
d3.event.sourceEvent.preventDefault();
|
|
|
|
var self = this;
|
|
|
|
var handler_d3 = d3.select(self._target + " .handler_" + handler);
|
|
|
|
switch (action) {
|
|
case "dragstart":
|
|
handler_d3.classed("dragging", true);
|
|
|
|
self.save_size_item(item);
|
|
break;
|
|
case "drag":
|
|
var delta_x = d3.event.dx;
|
|
var delta_y = d3.event.dy;
|
|
|
|
switch (handler) {
|
|
case "N":
|
|
case "S":
|
|
delta_x = 0;
|
|
break;
|
|
case "E":
|
|
case "W":
|
|
delta_y = 0;
|
|
break;
|
|
}
|
|
|
|
self.resize_node(item, handler, delta_x, delta_y);
|
|
|
|
self.positioning_resize_square(item);
|
|
break;
|
|
case "dragend":
|
|
handler_d3.classed("dragging", false);
|
|
|
|
var item_d3 = d3.select(self._target + " #node_" + item['graph_id']);
|
|
var width = parseFloat(item_d3.attr("data-width"));
|
|
var height = parseFloat(item_d3.attr("data-height"));
|
|
|
|
var transform_viewport =
|
|
d3.transform(item_d3.attr("transform"));
|
|
var x = transform_viewport.translate[0];
|
|
var y = transform_viewport.translate[1];
|
|
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (node['graph_id'] != item['graph_id'])
|
|
return 1; // Continue
|
|
|
|
self.get_nodes_map()[i].x = x;
|
|
self.get_nodes_map()[i].y = y;
|
|
self.get_nodes_map()[i].width = width;
|
|
self.get_nodes_map()[i].height = height;
|
|
});
|
|
|
|
self.resize_node_save(item['graph_id']);
|
|
break;
|
|
}
|
|
}
|
|
|
|
MapController.prototype.resize_node_save = function(graph_id) {
|
|
|
|
}
|
|
|
|
/**
|
|
* Function save_size_item
|
|
* Return void
|
|
* This function saves the actual size of the element (node)
|
|
*/
|
|
MapController.prototype.save_size_item = function(item) {
|
|
var self = this;
|
|
|
|
var item_d3 = d3.select(self._target + " #node_" + item['graph_id']);
|
|
var item_transform = d3.transform(item_d3.attr("transform"));
|
|
var item_bbox = item_d3.node().getBBox();
|
|
|
|
var width = item_bbox.width * item_transform.scale[0];
|
|
var height = item_bbox.height * item_transform.scale[1];
|
|
|
|
item_d3.attr("data-original_width", parseFloat(width));
|
|
item_d3.attr("data-original_height", parseFloat(height));
|
|
}
|
|
|
|
/**
|
|
* Function resize_node
|
|
* Return void
|
|
* This function do the process to resize the element (node)
|
|
*/
|
|
MapController.prototype.resize_node = function(item, handler, delta_x, delta_y) {
|
|
var self = this;
|
|
|
|
var item_d3 = d3.select(self._target + " #node_" + item['graph_id']);
|
|
var item_transform = d3.transform(item_d3.attr("transform"));
|
|
var item_bbox = item_d3.node().getBBox();
|
|
var transform_viewport =
|
|
d3.transform(d3.select(self._target + " .viewport").attr("transform"));
|
|
|
|
var inc_w = delta_x * transform_viewport.scale[0];
|
|
var inc_h = delta_y * transform_viewport.scale[1];
|
|
|
|
var width = item_d3.attr("data-width");
|
|
var height = item_d3.attr("data-height");
|
|
|
|
if (width == null) {
|
|
width = old_width = item_d3.attr("data-original_width");
|
|
height = old_height = item_d3.attr("data-original_height");
|
|
}
|
|
|
|
old_width = parseFloat(old_width);
|
|
old_height = parseFloat(old_height);
|
|
width = parseFloat(width);
|
|
height = parseFloat(height);
|
|
|
|
var new_width;
|
|
var new_height;
|
|
|
|
var scale_x;
|
|
var scale_y;
|
|
|
|
switch (handler) {
|
|
case "SE":
|
|
case "E":
|
|
case "S":
|
|
new_width = width + inc_w;
|
|
new_height = height + inc_h;
|
|
if ((new_width < 0) || (new_height < 0)) {
|
|
if ((new_width < 0) && (new_height < 0)) {
|
|
new_width = Math.abs(new_width);
|
|
new_height = Math.abs(new_height);
|
|
}
|
|
else if (new_width < 0) {
|
|
new_width = Math.abs(new_width);
|
|
}
|
|
else {
|
|
new_height = Math.abs(new_height);
|
|
}
|
|
}
|
|
break;
|
|
case "N":
|
|
case "NE":
|
|
new_width = width + inc_w;
|
|
new_height = height - inc_h;
|
|
if ((new_width < 0) || (new_height < 0)) {
|
|
if ((new_width < 0) && (new_height < 0)) {
|
|
new_width = Math.abs(new_width);
|
|
new_height = Math.abs(new_height);
|
|
}
|
|
else if (new_width < 0) {
|
|
new_width = Math.abs(new_width);
|
|
}
|
|
else {
|
|
new_height = Math.abs(new_height);
|
|
}
|
|
}
|
|
else {
|
|
item_transform.translate[1] += inc_h;
|
|
}
|
|
break;
|
|
case "NW":
|
|
case "W":
|
|
new_width = width - inc_w;
|
|
new_height = height - inc_h;
|
|
if ((new_width < 0) || (new_height < 0)) {
|
|
if ((new_width < 0) && (new_height < 0)) {
|
|
new_width = Math.abs(new_width);
|
|
new_height = Math.abs(new_height);
|
|
}
|
|
else if (new_width < 0) {
|
|
new_width = Math.abs(new_width);
|
|
}
|
|
else {
|
|
new_height = Math.abs(new_height);
|
|
}
|
|
}
|
|
else {
|
|
item_transform.translate[0] += inc_w;
|
|
item_transform.translate[1] += inc_h;
|
|
}
|
|
break;
|
|
case "SW":
|
|
new_width = width - inc_w;
|
|
new_height = height + inc_h;
|
|
if ((new_width < 0) || (new_height < 0)) {
|
|
if ((new_width < 0) && (new_height < 0)) {
|
|
new_width = Math.abs(new_width);
|
|
new_height = Math.abs(new_height);
|
|
}
|
|
else if (new_width < 0) {
|
|
new_width = Math.abs(new_width);
|
|
}
|
|
else {
|
|
new_height = Math.abs(new_height);
|
|
}
|
|
}
|
|
else {
|
|
item_transform.translate[0] += inc_w;
|
|
}
|
|
break;
|
|
}
|
|
|
|
scale_x = new_width / old_width;
|
|
scale_y = new_height / old_height;
|
|
|
|
item_transform.scale[0] = scale_x;
|
|
item_transform.scale[1] = scale_y;
|
|
|
|
item_d3.attr("transform", item_transform.toString());
|
|
|
|
item_d3.attr("data-width", parseFloat(new_width));
|
|
item_d3.attr("data-height", parseFloat(new_height));
|
|
|
|
|
|
self.move_arrow(item["graph_id"]);
|
|
}
|
|
|
|
/**
|
|
* Function key_is_pressed
|
|
* Return void
|
|
* This function checks if the crtl key is pressed
|
|
*/
|
|
MapController.prototype.key_is_pressed = function(key) {
|
|
var self = this;
|
|
|
|
if (typeof(self._keys_pressed[key]) == "undefined")
|
|
return false;
|
|
else
|
|
return self._keys_pressed[key];
|
|
}
|
|
|
|
/**
|
|
* Function get_menu_nodes
|
|
* Return void
|
|
* This function returns the node menu
|
|
*/
|
|
MapController.prototype.get_menu_nodes = function() {
|
|
var self = this;
|
|
|
|
var node_menu = [
|
|
{
|
|
title: 'Show details',
|
|
action: function(elm, d, i) {
|
|
var nodeTarget = $(elm);
|
|
var type = parseInt(nodeTarget.data("type"));
|
|
if (type == 0) {
|
|
self.nodeGetDetails(self, elm);
|
|
}
|
|
}
|
|
},
|
|
{
|
|
title: 'Resize',
|
|
action: function(elm, d, i) {
|
|
self.paint_resize_square(d);
|
|
}
|
|
},
|
|
{
|
|
title: 'Edit',
|
|
action: function(elm, d, i) {
|
|
self.editNode(elm);
|
|
}
|
|
},
|
|
{
|
|
title: 'Set as children',
|
|
action: function(elm, d, i) {
|
|
self._last_event = null;
|
|
self._relationship_in_progress_type = "children";
|
|
self.set_as_children();
|
|
}
|
|
},
|
|
{
|
|
title: 'Set as parent',
|
|
action: function(elm, d, i) {
|
|
self._last_event = null;
|
|
self._relationship_in_progress_type = "parent";
|
|
self.set_as_parent();
|
|
}
|
|
},
|
|
{
|
|
title: 'Delete',
|
|
action: function(elm, d, i) {
|
|
self.deleteNode(self, elm);
|
|
}
|
|
}
|
|
];
|
|
|
|
return node_menu;
|
|
}
|
|
|
|
/**
|
|
* Function events_for_minimap
|
|
* Return void
|
|
* This function init the minimap events
|
|
*/
|
|
MapController.prototype.events_for_minimap = function() {
|
|
var self = this;
|
|
|
|
d3.select(self._target + " .minimap")
|
|
.on("mouseover", function(d) {
|
|
self._over = "minimap";
|
|
})
|
|
.on("mouseout", function(d) {
|
|
self._over = null;
|
|
})
|
|
//~ .on("mousedown", function(d) {
|
|
//~ console.log("minimap mousedown");
|
|
//~ d3.event.stopPropagation();
|
|
//~ d3.event.preventDefault();
|
|
//~ })
|
|
//~ .on("mouseup", function(d) {
|
|
//~ console.log("minimap mouseup");
|
|
//~ d3.event.stopPropagation();
|
|
//~ d3.event.preventDefault();
|
|
//~ })
|
|
.on("click", function(d) {
|
|
//~ console.log("minimap click");
|
|
|
|
self.minimap_panning_map();
|
|
});
|
|
|
|
var drag = d3.behavior.drag()
|
|
.origin(function(d) { return d; })
|
|
.on("dragstart", function(d) {
|
|
console.log("dragstart minimap");
|
|
//~ self.event_resize("dragstart", item, d);
|
|
})
|
|
.on("drag", function(d) {
|
|
console.log("drag minimap");
|
|
})
|
|
.on("dragend", function(d) {
|
|
console.log("dragend minimap");
|
|
});
|
|
|
|
d3.select(self._target + " .minimap .viewport").call(drag);
|
|
}
|
|
|
|
/**
|
|
* Function map_move_position
|
|
* Return void
|
|
* This function moves map position with minimap click
|
|
*/
|
|
MapController.prototype.map_move_position = function(x, y) {
|
|
var self = this;
|
|
|
|
self._zoomManager
|
|
.translate([-x, -y])
|
|
.event(self._viewport);
|
|
}
|
|
|
|
/**
|
|
* Function minimap_panning_map
|
|
* Return void
|
|
* This function calculates the position in click event (minimap)
|
|
*/
|
|
MapController.prototype.minimap_panning_map = function() {
|
|
var self = this;
|
|
|
|
var minimap_translate = d3.transform(
|
|
d3.select(self._target +" .minimap").attr("transform")).translate;
|
|
|
|
var minimap_map_transform = d3.transform(
|
|
d3.select(self._target +" .minimap .map").attr("transform"));
|
|
|
|
var viewport_minimap = d3.select(self._target +" .minimap .viewport");
|
|
|
|
var x = self._last_mouse_position[0] - minimap_translate[0];
|
|
var y = self._last_mouse_position[1] - minimap_translate[1];
|
|
|
|
x = x / minimap_map_transform.scale[0] -
|
|
parseFloat(viewport_minimap.attr("width")) / 2;
|
|
y = y / minimap_map_transform.scale[0] -
|
|
parseFloat(viewport_minimap.attr("height")) / 2;
|
|
|
|
self.map_move_position(x, y);
|
|
}
|
|
|
|
/**
|
|
* Function events_for_nodes
|
|
* Return void
|
|
* This function init the nodes events
|
|
*/
|
|
MapController.prototype.events_for_nodes = function(id_node) {
|
|
var self = this;
|
|
|
|
var selector = ".node";
|
|
if (typeof(id_node) != "undefined") {
|
|
selector = "#node_" + id_node;
|
|
}
|
|
|
|
var node_menu = self.get_menu_nodes();
|
|
|
|
d3.selectAll(selector)
|
|
.on("mouseover", function(d) {
|
|
if (!self._dragging) {
|
|
self.select_node(d['graph_id'], "over");
|
|
}
|
|
|
|
self.last_event = null;
|
|
})
|
|
.on("mouseout", function(d) {
|
|
if (!self._dragging) {
|
|
var status_selection = self.get_status_selection_node(d['graph_id']);
|
|
|
|
self.select_node(d['graph_id'], "off");
|
|
if (status_selection.indexOf("select") != -1) {
|
|
self.select_node(d['graph_id'], "select");
|
|
}
|
|
}
|
|
})
|
|
.on("click", function(d) {
|
|
if (self.last_event == "relationship") {
|
|
self.last_event = null;
|
|
return;
|
|
}
|
|
|
|
if (d3.event.button != 0) {
|
|
d3.event.stopPropagation();
|
|
d3.event.preventDefault();
|
|
}
|
|
|
|
if (d3.event.defaultPrevented) return;
|
|
|
|
if ((d['type'] == ITEM_TYPE_AGENT_NETWORKMAP) || (d['type'] == ITEM_TYPE_MODULE_NETWORKMAP) ||
|
|
(d['type'] == ITEM_TYPE_GROUP_NETWORKMAP) || (d['type'] == ITEM_TYPE_POLICY_NETWORKMAP)) {
|
|
self.tooltip_map_create(self, this);
|
|
}
|
|
})
|
|
.on("contextmenu", d3.contextMenu(node_menu, function(node) {
|
|
self._last_event = "contextmenu";
|
|
self.select_node(node['graph_id'], "select");
|
|
}));
|
|
|
|
var drag = d3.behavior.drag()
|
|
.origin(function(d) { return d; })
|
|
.on("dragstart", dragstarted)
|
|
.on("drag", dragged)
|
|
.on("dragend", dragended);
|
|
|
|
d3.selectAll(selector).call(drag);
|
|
|
|
|
|
/**
|
|
* Function dragstarted
|
|
* Return void
|
|
*/
|
|
function dragstarted(d) {
|
|
if (d3.event.sourceEvent.button == 0) {
|
|
d3.event.sourceEvent.stopPropagation();
|
|
d3.event.sourceEvent.preventDefault();
|
|
}
|
|
|
|
if (self._relationship_in_progress) {
|
|
return;
|
|
}
|
|
|
|
if ($("#node_" + d['graph_id']).hasClass("tooltipstered")) {
|
|
$("#node_" + d['graph_id']).tooltipster('destroy');
|
|
}
|
|
|
|
self.remove_resize_square();
|
|
|
|
var status_selection = self.get_status_selection_node(d['graph_id']);
|
|
|
|
if (status_selection.indexOf("select") == -1) {
|
|
self.remove_selection_nodes();
|
|
}
|
|
|
|
self.select_node(d['graph_id'], "select");
|
|
|
|
self._dragging = true;
|
|
self._dragged_nodes = {};
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (!self.is_draggable(node))
|
|
return 1; // Continue
|
|
|
|
var status_selection =
|
|
self.get_status_selection_node(node.graph_id);
|
|
|
|
if (status_selection.indexOf("select") == -1) {
|
|
return 1; // Continue
|
|
}
|
|
|
|
self._dragged_nodes[node.graph_id] = {};
|
|
self._dragged_nodes[node.graph_id]['old_x'] = node.x;
|
|
self._dragged_nodes[node.graph_id]['old_y'] = node.y;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function dragged
|
|
* Return void
|
|
*/
|
|
function dragged(d) {
|
|
var delta_x = d3.event.dx;
|
|
var delta_y = d3.event.dy;
|
|
|
|
self._dragging = true;
|
|
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (!self.is_draggable(node))
|
|
return 1; // Continue
|
|
|
|
var status_selection =
|
|
self.get_status_selection_node(node.graph_id);
|
|
|
|
if (status_selection.indexOf("select") == -1) {
|
|
return 1; // Continue
|
|
}
|
|
|
|
var d3_node = d3.select(self._target + " #node_" + node.graph_id);
|
|
|
|
var transform = d3.transform(d3_node.attr("transform"));
|
|
|
|
transform.translate[0] += delta_x;
|
|
transform.translate[1] += delta_y;
|
|
|
|
self.get_nodes_map()[i].x = transform.translate[0];
|
|
self.get_nodes_map()[i].y = transform.translate[1];
|
|
|
|
d3.select(self._target + " .minimap #node_" + node.graph_id)
|
|
.attr("transform", transform.toString());
|
|
|
|
d3_node.attr("transform", transform.toString());
|
|
|
|
self.move_arrow(node.graph_id);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function dragended
|
|
* Return void
|
|
*/
|
|
function dragended(d) {
|
|
if (self._last_event != "contextmenu") {
|
|
self._last_event = null;
|
|
|
|
|
|
$.each(self._dragged_nodes, function(id_node, old_values) {
|
|
var node = self.get_node(id_node);
|
|
|
|
self.move_node(node);
|
|
});
|
|
|
|
self._dragged_nodes = {};
|
|
|
|
self.select_node(d['graph_id'], "off");
|
|
|
|
if ($("#node_" + d['graph_id']).hasClass("tooltipstered")) {
|
|
$("#node_" + d['graph_id']).tooltipster('destroy');
|
|
}
|
|
|
|
self.remove_resize_square();
|
|
|
|
self._dragging = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
MapController.prototype.move_node = function(node) {
|
|
}
|
|
|
|
/**
|
|
* Function is_draggable
|
|
* Return void
|
|
* This function checks if the node is draggable
|
|
*/
|
|
MapController.prototype.is_draggable = function(node) {
|
|
var self = this;
|
|
|
|
var return_var = false;
|
|
|
|
switch (node.type) {
|
|
case ITEM_TYPE_MODULE_NETWORKMAP:
|
|
if (self.get_filter_map()['show_modules']) {
|
|
return_var = true;
|
|
}
|
|
else {
|
|
return_var = false;
|
|
}
|
|
break;
|
|
case ITEM_TYPE_MODULEGROUP_NETWORKMAP:
|
|
if (self.get_filter_map()['show_modules']) {
|
|
if (self.get_filter_map()['show_module_group']) {
|
|
return_var = true;
|
|
}
|
|
else {
|
|
return_var = false;
|
|
}
|
|
}
|
|
else {
|
|
return_var = false;
|
|
}
|
|
break;
|
|
case ITEM_TYPE_AGENT_NETWORKMAP:
|
|
case ITEM_TYPE_GROUP_NETWORKMAP:
|
|
case ITEM_TYPE_POLICY_NETWORKMAP:
|
|
case ITEM_TYPE_FICTIONAL_NODE:
|
|
return_var = true;
|
|
break;
|
|
}
|
|
|
|
return return_var;
|
|
}
|
|
|
|
/**
|
|
* Function is_relationshipy
|
|
* Return void
|
|
* This function checks if the node have a relathion
|
|
*/
|
|
MapController.prototype.is_relationshipy = function(node) {
|
|
var return_var = false;
|
|
|
|
switch (node.type) {
|
|
case ITEM_TYPE_AGENT_NETWORKMAP:
|
|
case ITEM_TYPE_FICTIONAL_NODE:
|
|
return_var = true;
|
|
break;
|
|
}
|
|
|
|
return return_var;
|
|
}
|
|
|
|
/**
|
|
* Function is_selecty
|
|
* Return void
|
|
* This function checks if the node is selecty
|
|
*/
|
|
MapController.prototype.is_selecty = function(node) {
|
|
var self = this;
|
|
|
|
var return_var = false;
|
|
|
|
switch (node.type) {
|
|
case ITEM_TYPE_AGENT_NETWORKMAP:
|
|
case ITEM_TYPE_FICTIONAL_NODE:
|
|
case ITEM_TYPE_GROUP_NETWORKMAP:
|
|
case ITEM_TYPE_POLICY_NETWORKMAP:
|
|
return_var = true;
|
|
break;
|
|
case ITEM_TYPE_MODULE_NETWORKMAP:
|
|
if (self.get_filter_map()['show_modules']) {
|
|
return_var = true;
|
|
}
|
|
else {
|
|
return_var = false;
|
|
}
|
|
break;
|
|
case ITEM_TYPE_MODULEGROUP_NETWORKMAP:
|
|
if (self.get_filter_map()['show_modules']) {
|
|
if (self.get_filter_map()['show_module_group']) {
|
|
return_var = true;
|
|
}
|
|
else {
|
|
return_var = false;
|
|
}
|
|
}
|
|
else {
|
|
return_var = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return return_var;
|
|
}
|
|
|
|
/**
|
|
* Function is_delety
|
|
* Return void
|
|
* This function checks if the node is delety
|
|
*/
|
|
MapController.prototype.is_delety = function(node) {
|
|
var self = this;
|
|
|
|
var return_var = false;
|
|
|
|
switch (node.type) {
|
|
case ITEM_TYPE_AGENT_NETWORKMAP:
|
|
case ITEM_TYPE_FICTIONAL_NODE:
|
|
case ITEM_TYPE_GROUP_NETWORKMAP:
|
|
case ITEM_TYPE_POLICY_NETWORKMAP:
|
|
return_var = true;
|
|
break;
|
|
case ITEM_TYPE_MODULE_NETWORKMAP:
|
|
if (self.get_filter_map()['show_modules']) {
|
|
return_var = true;
|
|
}
|
|
else {
|
|
return_var = false;
|
|
}
|
|
break;
|
|
case ITEM_TYPE_MODULEGROUP_NETWORKMAP:
|
|
if (self.get_filter_map()['show_modules']) {
|
|
if (self.get_filter_map()['show_module_group']) {
|
|
return_var = true;
|
|
}
|
|
else {
|
|
return_var = false;
|
|
}
|
|
}
|
|
else {
|
|
return_var = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return return_var;
|
|
}
|
|
|
|
/**
|
|
* Function init_events
|
|
* Return boolean
|
|
* This function init click events in the map
|
|
*/
|
|
MapController.prototype.events = function() {
|
|
var self = this;
|
|
|
|
self.events_for_nodes();
|
|
|
|
d3.select("body")
|
|
.on("keydown", function() {
|
|
// ctrl key
|
|
if (d3.event.keyCode === CONTROL_KEY) {
|
|
self._start_flag_multiple_selection = true;
|
|
self.multiple_selection_start();
|
|
|
|
self._keys_pressed[CONTROL_KEY] = true;
|
|
}
|
|
})
|
|
.on("keyup", function() {
|
|
if (d3.event.keyCode === CONTROL_KEY) {
|
|
self.multiple_selection_end();
|
|
self._last_event = "multiple_selection_end";
|
|
|
|
self._keys_pressed[CONTROL_KEY] = false;
|
|
}
|
|
});
|
|
|
|
var map_menu = [
|
|
{
|
|
title: 'Add fictional node',
|
|
action: function(elm, d, i) {
|
|
self.add_fictional_node();
|
|
}
|
|
}
|
|
];
|
|
|
|
d3.select(self._target).on("contextmenu", d3.contextMenu(map_menu));
|
|
|
|
d3.select(self._target + " svg").on("mousedown",
|
|
function() {
|
|
if (self._start_flag_multiple_selection) {
|
|
self._start_flag_multiple_selection = false;
|
|
self._flag_multiple_selection = true;
|
|
}
|
|
if (self._flag_multiple_selection) {
|
|
|
|
self.multiple_selection_dragging(
|
|
d3.event.offsetX,
|
|
d3.event.offsetY, true);
|
|
}
|
|
|
|
d3.event.stopPropagation();
|
|
d3.event.preventDefault();
|
|
});
|
|
|
|
d3.select(self._target + " svg").on("mouseup",
|
|
function(d) {
|
|
if (self._over == "minimap")
|
|
return;
|
|
|
|
if (self._last_event == "multiple_selection_end") {
|
|
self._last_event = null;
|
|
return;
|
|
}
|
|
|
|
if (!self._flag_multiple_selection) {
|
|
if (self.last_event != "zoom") {
|
|
self.last_event = null;
|
|
|
|
if (self._relationship_in_progress) {
|
|
|
|
var found_id = null;
|
|
for (i in d3.event.path) {
|
|
var item = d3.event.path[i];
|
|
|
|
if (item == document)
|
|
continue;
|
|
if (typeof(d3.select(item).node().tagName) == "undefined")
|
|
continue;
|
|
|
|
if (d3.select(item).classed("node")) {
|
|
found_id = d3.select(item).attr("data-graph_id");
|
|
}
|
|
}
|
|
|
|
|
|
if (found_id !== null) {
|
|
self.apply_temp_arrows(found_id);
|
|
}
|
|
else {
|
|
self.remove_temp_arrows();
|
|
}
|
|
|
|
|
|
self.last_event = "relationship";
|
|
|
|
self.hide_help_text_in_pointer();
|
|
}
|
|
|
|
self.remove_selection_nodes();
|
|
}
|
|
else {
|
|
self.last_event = null;
|
|
}
|
|
}
|
|
else {
|
|
self.multiple_selection_end();
|
|
}
|
|
});
|
|
|
|
d3.select(self._target + " svg").on("mousemove",
|
|
function() {
|
|
if (self._flag_multiple_selection) {
|
|
self.multiple_selection_dragging(
|
|
d3.event.offsetX,
|
|
d3.event.offsetY, false);
|
|
}
|
|
});
|
|
|
|
d3.select(self._target).on("mousemove",
|
|
function() {
|
|
var map_pos = d3.select(self._target).node().getBoundingClientRect();
|
|
|
|
var x = d3.event.pageX - map_pos.left;
|
|
var y = d3.event.pageY - map_pos.top;;
|
|
|
|
self._last_mouse_position = [x, y];
|
|
|
|
if (self._relationship_in_progress) {
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (!self.is_relationshipy(node))
|
|
return 1; // Continue
|
|
|
|
var status_selection =
|
|
self.get_status_selection_node(node.graph_id);
|
|
|
|
if (status_selection.indexOf("select") == -1) {
|
|
return 1; // Continue
|
|
}
|
|
|
|
self._relationship_in_progress = true;
|
|
self.move_temp_arrows(node,
|
|
self._relationship_in_progress_type);
|
|
self.show_help_text_in_pointer();
|
|
});
|
|
}
|
|
});
|
|
|
|
setTimeout(function() { self.refresh_map();}, self._refresh_time);
|
|
}
|
|
|
|
/**
|
|
* Function refresh_map
|
|
* Return void
|
|
* This function refresh the map
|
|
*/
|
|
MapController.prototype.refresh_map = function() {
|
|
var self = this;
|
|
|
|
self.refresh_nodes();
|
|
self.refresh_arrows();
|
|
|
|
setTimeout(function() { self.refresh_map();}, self._refresh_time);
|
|
}
|
|
|
|
/**
|
|
* Function set_as_parent
|
|
* Return void
|
|
* This function sets a node as a parent
|
|
*/
|
|
MapController.prototype.set_as_parent = function() {
|
|
var self = this;
|
|
|
|
self.start_relationship_nodes("parent");
|
|
}
|
|
|
|
/**
|
|
* Function set_as_children
|
|
* Return void
|
|
* This function sets a node as a children
|
|
*/
|
|
MapController.prototype.set_as_children = function() {
|
|
var self = this;
|
|
|
|
self.start_relationship_nodes("children");
|
|
}
|
|
|
|
/**
|
|
* Function start_relationship_nodes
|
|
* Return void
|
|
* This function starts the relation nodes function
|
|
*/
|
|
MapController.prototype.start_relationship_nodes = function(type) {
|
|
var self = this;
|
|
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (!self.is_relationshipy(node))
|
|
return 1; // Continue
|
|
|
|
var status_selection =
|
|
self.get_status_selection_node(node.graph_id);
|
|
|
|
if (status_selection.indexOf("select") == -1) {
|
|
return 1; // Continue
|
|
}
|
|
|
|
self._relationship_in_progress = true;
|
|
self._dragging = false;
|
|
self.show_temp_arrows(node, type);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function show_temp_arrows
|
|
* Return void
|
|
* This function shows temporal arrows to parent-children relation
|
|
*/
|
|
MapController.prototype.show_temp_arrows = function(node, type) {
|
|
var self = this;
|
|
|
|
// Apply the zoom and panning
|
|
var zoom = d3.transform(
|
|
d3.select(self._target + " .viewport").attr("transform"));
|
|
|
|
var x = self._last_mouse_position[0]/ zoom.scale[0]
|
|
- zoom.translate[0] / zoom.scale[0];
|
|
|
|
var y = self._last_mouse_position[1]/ zoom.scale[1]
|
|
- zoom.translate[1] / zoom.scale[1];
|
|
|
|
var temp_arrow = {};
|
|
temp_arrow['graph_id'] = "temp_" + node.graph_id;
|
|
temp_arrow['mouse'] = [x, y];
|
|
temp_arrow['temp'] = 1;
|
|
temp_arrow['type'] = type;
|
|
temp_arrow['from'] = {};
|
|
temp_arrow['to'] = {};
|
|
|
|
if (d3.select(self._target + " #arrow_temp_" + node.graph_id).empty()) {
|
|
self._viewport
|
|
.append("g")
|
|
.attr("class", "arrow")
|
|
.attr("id", function(d) {
|
|
return "arrow_temp_" + node.graph_id;})
|
|
.attr("data-id", function(d) { return node.graph_id;})
|
|
.attr("data-temp", 1);
|
|
}
|
|
|
|
switch (type) {
|
|
case 'parent':
|
|
temp_arrow['from']['graph_id'] = node.graph_id;
|
|
temp_arrow['to']['graph_id'] = null;
|
|
break;
|
|
case 'children':
|
|
temp_arrow['from']['graph_id'] = null;
|
|
temp_arrow['to']['graph_id'] = node.graph_id;
|
|
break;
|
|
}
|
|
|
|
self.arrow_by_pieces(self._target + " svg", temp_arrow);
|
|
}
|
|
|
|
/**
|
|
* Function move_temp_arrows
|
|
* Return void
|
|
* This function move the temporal arrows
|
|
*/
|
|
MapController.prototype.move_temp_arrows = function(node, type) {
|
|
var self = this;
|
|
|
|
// Apply the zoom and panning
|
|
var zoom = d3.transform(
|
|
d3.select(self._target + " .viewport").attr("transform"));
|
|
|
|
var x = self._last_mouse_position[0]/ zoom.scale[0]
|
|
- zoom.translate[0] / zoom.scale[0];
|
|
|
|
var y = self._last_mouse_position[1]/ zoom.scale[1]
|
|
- zoom.translate[1] / zoom.scale[1];
|
|
|
|
var temp_arrow = {};
|
|
temp_arrow['graph_id'] = "temp_" + node.graph_id;
|
|
temp_arrow['mouse'] = [x, y];
|
|
temp_arrow['temp'] = 1;
|
|
temp_arrow['type'] = type;
|
|
temp_arrow['from'] = {};
|
|
temp_arrow['to'] = {};
|
|
|
|
switch (type) {
|
|
case 'parent':
|
|
temp_arrow['from']['graph_id'] = node.graph_id;
|
|
temp_arrow['to']['graph_id'] = null;
|
|
break;
|
|
case 'children':
|
|
temp_arrow['from']['graph_id'] = null;
|
|
temp_arrow['to']['graph_id'] = node.graph_id;
|
|
break;
|
|
}
|
|
|
|
|
|
self.arrow_by_pieces(self._target + " svg", temp_arrow, 0);
|
|
}
|
|
|
|
MapController.prototype.hide_help_text_in_pointer = function() {
|
|
var self = this;
|
|
|
|
d3.select(self._target + " .help_text_pointer").remove();
|
|
}
|
|
|
|
MapController.prototype.show_help_text_in_pointer = function() {
|
|
var self = this;
|
|
|
|
var zoom = d3.transform(
|
|
d3.select(self._target + " .viewport").attr("transform"));
|
|
|
|
var x = self._last_mouse_position[0]/ zoom.scale[0]
|
|
- zoom.translate[0] / zoom.scale[0];
|
|
|
|
var y = self._last_mouse_position[1]/ zoom.scale[1]
|
|
- zoom.translate[1] / zoom.scale[1];
|
|
|
|
var help_text_pointer = d3.select(self._target + " .help_text_pointer");
|
|
|
|
if (help_text_pointer.node() == null) {
|
|
help_text_pointer = d3.select(self._target + " svg").append("g")
|
|
.attr("class", "help_text_pointer");
|
|
|
|
|
|
var rect_background_help=
|
|
help_text_pointer.append("rect").attr("class", ".rect_background_help");
|
|
|
|
help_text_pointer.append("text")
|
|
.text("Click in anynode to link")
|
|
.attr("x", 3).attr("y", 12);
|
|
|
|
var bbox = help_text_pointer.node().getBBox()
|
|
|
|
rect_background_help.attr("x", 0).attr("y", 0)
|
|
.attr("height", bbox.height)
|
|
.attr("width", bbox.width + 5)
|
|
.attr("style", "opacity:1;fill:#feffb4;fill-opacity:1;stroke:#808080;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1");
|
|
}
|
|
|
|
|
|
var transform = d3.transform();
|
|
|
|
transform.translate[0] = x;
|
|
transform.translate[1] = y + 20; // Under the mouse pointer
|
|
|
|
help_text_pointer.attr("transform", transform.toString());
|
|
}
|
|
|
|
/**
|
|
* Function remove_temp_arrows
|
|
* Return void
|
|
* This function remove the temporal arrows
|
|
*/
|
|
MapController.prototype.remove_temp_arrows = function() {
|
|
var self = this;
|
|
|
|
d3.selectAll(self._target + " .arrow")
|
|
.filter(function(d, i) {
|
|
if (d3.select(this).attr("data-temp") == 1) return true;
|
|
else return false;
|
|
})
|
|
.remove();
|
|
|
|
self._relationship_in_progress = false;
|
|
self._relationship_in_progress_type = null;
|
|
}
|
|
|
|
/**
|
|
* Function apply_temp_arrows
|
|
* Return void
|
|
* This function apply the temporal arrows
|
|
*/
|
|
MapController.prototype.apply_temp_arrows = function(target_id) {
|
|
var self = this;
|
|
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (!self.is_relationshipy(node))
|
|
return 1; // Continue
|
|
|
|
var status_selection =
|
|
self.get_status_selection_node(node.graph_id);
|
|
|
|
if (status_selection.indexOf("select") == -1) {
|
|
return 1; // Continue
|
|
}
|
|
|
|
switch (self._relationship_in_progress_type) {
|
|
case 'parent':
|
|
self.make_arrow(node.graph_id, target_id);
|
|
break;
|
|
case 'children':
|
|
self.make_arrow(target_id, node.graph_id);
|
|
break;
|
|
}
|
|
});
|
|
|
|
self.remove_temp_arrows();
|
|
self.paint_arrows();
|
|
}
|
|
|
|
/**
|
|
* Function get_status_selection_node
|
|
* Return node status
|
|
* This function returns the status of a node
|
|
*/
|
|
MapController.prototype.get_status_selection_node = function(id_node) {
|
|
var self = this;
|
|
|
|
var status = d3.select(self._target + " #node_" + id_node)
|
|
.attr("data-select");
|
|
|
|
if (status === null) {
|
|
return [];
|
|
}
|
|
else {
|
|
return status.split(" ");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function multiple_selection_start
|
|
* Return void
|
|
* This function init multiple selection mode
|
|
*/
|
|
MapController.prototype.multiple_selection_start = function() {
|
|
var self = this;
|
|
|
|
if (!self._cache_files.hasOwnProperty("selection_box")) {
|
|
var selection_box = d3
|
|
.select(self._target + " svg")
|
|
.append("g").attr("id", "selection_box")
|
|
.style("opacity", 0);
|
|
|
|
d3.xml("images/maps/selection_box.svg", "application/xml", function(xml) {
|
|
var nodes = xml
|
|
.evaluate("//*[@id='selection_box']/*", xml, null,
|
|
XPathResult.ANY_TYPE, null);
|
|
|
|
self._cache_files["selection_box"] = nodes.iterateNext();
|
|
|
|
self.multiple_selection_start();
|
|
});
|
|
}
|
|
else {
|
|
var selection_box = d3
|
|
.select(self._target + " #selection_box");
|
|
|
|
selection_box
|
|
.append(function() {
|
|
return self._cache_files["selection_box"];
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function add_fictional_node
|
|
* Return void
|
|
* This function add a fictional node
|
|
*/
|
|
MapController.prototype.add_fictional_node = function() {
|
|
var self = this;
|
|
|
|
// Apply the zoom and panning
|
|
var zoom = d3.transform(
|
|
d3.select(self._target + " .viewport").attr("transform"));
|
|
|
|
var x = self._last_mouse_position[0] / zoom.scale[0]
|
|
- zoom.translate[0] / zoom.scale[0];
|
|
var y = self._last_mouse_position[1] / zoom.scale[1]
|
|
- zoom.translate[1] / zoom.scale[1];
|
|
|
|
var new_node = {};
|
|
|
|
new_node['id'] = 0;
|
|
new_node['id_agent'] = 0
|
|
new_node['graph_id'] = self.get_last_graph_id() + 1;
|
|
new_node['height'] = 30;
|
|
new_node['width'] = 30;
|
|
new_node['status'] = AGENT_MODULE_STATUS_NO_DATA;
|
|
new_node['title'] = "fictional point";
|
|
new_node['type'] = ITEM_TYPE_FICTIONAL_NODE;
|
|
new_node['x'] = x;
|
|
new_node['y'] = y;
|
|
|
|
self.get_nodes_map().push(new_node);
|
|
|
|
self.paint_nodes();
|
|
self.paint_items_minimap();
|
|
|
|
self.events_for_nodes(new_node['graph_id']);
|
|
}
|
|
|
|
/**
|
|
* Function get_last_graph_id
|
|
* Return id
|
|
* This function returns the last graph id
|
|
*/
|
|
MapController.prototype.get_last_graph_id = function() {
|
|
var self = this;
|
|
|
|
var return_var = 0;
|
|
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (node['graph_id'] > return_var) {
|
|
return_var = parseInt(node['graph_id']);
|
|
}
|
|
});
|
|
|
|
return return_var;
|
|
}
|
|
|
|
/**
|
|
* Function multiple_selection_dragging
|
|
* Return void
|
|
* This function init multiple selection drag
|
|
*/
|
|
MapController.prototype.multiple_selection_dragging = function(x, y, first) {
|
|
var self = this;
|
|
|
|
var selection_box = d3
|
|
.select(self._target + " #selection_box");
|
|
|
|
var transform = d3.transform();
|
|
|
|
if (first) {
|
|
transform.translate[0] = x;
|
|
transform.translate[1] = y;
|
|
|
|
selection_box.attr("transform", transform.toString());
|
|
selection_box.style("opacity", 1);
|
|
|
|
selection_box.select("rect")
|
|
.attr("width", 0);
|
|
selection_box.select("rect")
|
|
.attr("height", 0);
|
|
|
|
selection_box.attr("data-ini_x", x);
|
|
selection_box.attr("data-ini_y", y);
|
|
}
|
|
else {
|
|
var delta_x = x - parseInt(selection_box.attr("data-ini_x"));
|
|
var delta_y = y - parseInt(selection_box.attr("data-ini_y"));
|
|
|
|
if (delta_x < 0) {
|
|
transform = d3.transform(selection_box.attr("transform"));
|
|
|
|
transform.translate[0] = x;
|
|
|
|
selection_box.attr("transform", transform.toString());
|
|
|
|
selection_box.select("rect")
|
|
.attr("width", -delta_x);
|
|
}
|
|
else {
|
|
selection_box.select("rect")
|
|
.attr("width", delta_x);
|
|
}
|
|
|
|
if (delta_y < 0) {
|
|
transform = d3.transform(selection_box.attr("transform"));
|
|
|
|
transform.translate[1] = y;
|
|
|
|
selection_box.attr("transform", transform.toString());
|
|
|
|
selection_box.select("rect")
|
|
.attr("height", -delta_y);
|
|
}
|
|
else {
|
|
selection_box.select("rect")
|
|
.attr("height", delta_y);
|
|
}
|
|
|
|
self.multiple_selection_select_nodes();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function multiple_selection_end
|
|
* Return void
|
|
* This function ends multiple selection mode
|
|
*/
|
|
MapController.prototype.multiple_selection_end = function() {
|
|
var self = this;
|
|
|
|
self._flag_multiple_selection = false;
|
|
|
|
var selection_box = d3
|
|
.select(self._target + " #selection_box");
|
|
|
|
selection_box.style("opacity", 0);
|
|
selection_box.select("rect")
|
|
.attr("width", 0);
|
|
selection_box.select("rect")
|
|
.attr("height", 0);
|
|
}
|
|
|
|
/**
|
|
* Function multiple_selection_select_nodes
|
|
* Return void
|
|
* This function gets the nodes in the selection zone
|
|
*/
|
|
MapController.prototype.multiple_selection_select_nodes = function() {
|
|
var self = this;
|
|
|
|
var selection_box = d3
|
|
.select(self._target + " #selection_box");
|
|
var transform = d3.transform(selection_box.attr("transform"));
|
|
var selection_box_dimensions = {};
|
|
selection_box_dimensions["x"] = transform.translate[0];
|
|
selection_box_dimensions["y"] = transform.translate[1];
|
|
selection_box_dimensions["width"] = selection_box.select("rect")
|
|
.attr("width");
|
|
selection_box_dimensions["height"] = selection_box.select("rect")
|
|
.attr("height");
|
|
|
|
// Apply the zoom and panning
|
|
var zoom = d3.transform(
|
|
d3.select(self._target + " .viewport").attr("transform"));
|
|
|
|
|
|
selection_box_dimensions["x"] = (selection_box_dimensions["x"] / zoom.scale[0]
|
|
- zoom.translate[0] / zoom.scale[0]);
|
|
selection_box_dimensions["y"] = (selection_box_dimensions["y"] / zoom.scale[1]
|
|
- zoom.translate[1] / zoom.scale[1]);
|
|
|
|
selection_box_dimensions["width"] =
|
|
selection_box_dimensions["width"] / zoom.scale[0];
|
|
selection_box_dimensions["height"] =
|
|
selection_box_dimensions["height"] / zoom.scale[1];
|
|
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (!self.is_selecty(node))
|
|
return 1; // Continue
|
|
|
|
var x = parseFloat(node.x);
|
|
var y = parseFloat(node.y);
|
|
|
|
var node_bbox = null;
|
|
|
|
var width;
|
|
if (!node.hasOwnProperty("width")) {
|
|
node_bbox =
|
|
d3.select(self._target + " #node_" + node.graph_id).node().getBBox()
|
|
|
|
width = node_bbox['x'] + node_bbox['width'];
|
|
|
|
self.get_nodes_map()[i].width = width;
|
|
}
|
|
else {
|
|
width = node.width;
|
|
}
|
|
|
|
var height;
|
|
if (!node.hasOwnProperty("height")) {
|
|
if (node_bbox === null) {
|
|
node_bbox =
|
|
d3.select(self._target + " #node_" + node.graph_id).node().getBBox()
|
|
}
|
|
|
|
height = node_bbox['y'] + node_bbox['height'];
|
|
|
|
self.get_nodes_map()[i].height = height;
|
|
}
|
|
else {
|
|
height = node.height;
|
|
}
|
|
|
|
if (
|
|
(x >= selection_box_dimensions["x"]) &&
|
|
(y >= selection_box_dimensions["y"]) &&
|
|
((x + width) <= (selection_box_dimensions["x"] + selection_box_dimensions["width"])) &&
|
|
((y + height) <= (selection_box_dimensions["y"] + selection_box_dimensions["height"]))
|
|
) {
|
|
|
|
self.select_node(node.graph_id, "select");
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function remove_selection_nodes
|
|
* Return void
|
|
* This function removes the selection
|
|
*/
|
|
MapController.prototype.remove_selection_nodes = function() {
|
|
var self = this;
|
|
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (!self.is_selecty(node))
|
|
return 1; // Continue
|
|
|
|
self.select_node(node.graph_id, "off");
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function select_node
|
|
* Return void
|
|
* This function gets the node eith selection mode
|
|
*/
|
|
MapController.prototype.select_node = function(node_id, type) {
|
|
var self = this;
|
|
|
|
d3.select(self._target + " #node_" + node_id)
|
|
.classed("over", false);
|
|
|
|
var data = "";
|
|
switch (type) {
|
|
case 'select':
|
|
d3.select(self._target + " #node_" + node_id)
|
|
.classed("select", true);
|
|
d3.select(self._target + " #node_" + node_id)
|
|
.attr("style", "fill: rgb(50, 128, 50);");
|
|
data = "select";
|
|
break;
|
|
case 'over':
|
|
d3.select(self._target + " #node_" + node_id)
|
|
.classed("over", true);
|
|
|
|
var over_color =
|
|
d3.rgb(
|
|
d3.select(self._target + " #node_" + node_id)
|
|
.style("fill"))
|
|
.brighter(1).toString();
|
|
|
|
if (d3.select(self._target + " #node_" + node_id)
|
|
.classed("select")) {
|
|
|
|
d3.select(self._target + " #node_" + node_id)
|
|
.style("fill", over_color);
|
|
|
|
data = "select over";
|
|
}
|
|
else {
|
|
d3.select(self._target + " #node_" + node_id)
|
|
.style("fill", over_color);
|
|
|
|
data = "over";
|
|
}
|
|
break;
|
|
case 'off':
|
|
var status_color = d3
|
|
.select(self._target + " #node_" + node_id)
|
|
.attr("data-status_color");
|
|
|
|
d3.select(self._target + " #node_" + node_id)
|
|
.classed("select", false);
|
|
|
|
d3.select(self._target + " #node_" + node_id)
|
|
.style("fill", status_color);
|
|
break;
|
|
}
|
|
|
|
d3.select(self._target + " #node_" + node_id)
|
|
.attr("data-select", data);
|
|
}
|
|
|
|
/**
|
|
* Function tooltip_map_create
|
|
* Return void
|
|
* This function manages nodes tooltips
|
|
*/
|
|
MapController.prototype.tooltip_map_create = function(self, target) {
|
|
var nodeTarget = $(target);
|
|
var spinner = $('#spinner_tooltip').html();
|
|
var nodeSize = get_size_element("#" + $(nodeTarget).attr("id"));
|
|
nodeSize[0] = nodeSize[0] * self._zoomManager.scale(); // Apply zoom
|
|
var node_id = nodeTarget.attr("id");
|
|
|
|
var type = parseInt(nodeTarget.data("type"));
|
|
var data_id = parseInt(nodeTarget.data("id"));
|
|
var data_graph_id = parseInt(nodeTarget.data("graph_id"));
|
|
|
|
nodeTarget.tooltipster({
|
|
arrow: true,
|
|
trigger: 'click',
|
|
contentAsHTML: true,
|
|
autoClose: false,
|
|
offsetX: nodeSize[0] / 2,
|
|
theme: 'tooltipster-noir',
|
|
multiple: true,
|
|
interactive: true,
|
|
content: spinner,
|
|
restoration: 'none',
|
|
functionBefore: function(origin, continueTooltip) {
|
|
continueTooltip();
|
|
self.nodeData(data_id, type, self._id, data_graph_id, origin, node_id);
|
|
}
|
|
});
|
|
|
|
nodeTarget.tooltipster("show");
|
|
}
|
|
|
|
/**
|
|
* Function editMap
|
|
* Return void
|
|
* This function prints the map edition table
|
|
*/
|
|
MapController.prototype.editMap = function(self, target) {
|
|
var id_map = self._id;
|
|
|
|
var params = {};
|
|
params["printEditMapTable"] = 1;
|
|
params["id_map"] = id_map;
|
|
params["page"] = "include/ajax/map.ajax";
|
|
|
|
jQuery.ajax ({
|
|
data: params,
|
|
dataType: "html",
|
|
type: "POST",
|
|
url: "ajax.php",
|
|
success: function (data) {
|
|
$(target).append("<div id='edit_map_dialog' style='display: none;'></div>");
|
|
$("#edit_map_dialog").append(data);
|
|
$("#edit_map_dialog").dialog({ autoOpen: false });
|
|
$("#edit_map_dialog").dialog("open");
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function nodeGetDetails
|
|
* Return link
|
|
* This function returns a link with node details
|
|
*/
|
|
MapController.prototype.nodeGetDetails = function(self, target) {
|
|
var nodeTarget = $(target);
|
|
var node_id = nodeTarget.attr("id");
|
|
var data_id = parseInt(nodeTarget.data("id"));
|
|
var data_graph_id = parseInt(nodeTarget.data("graph_id"));
|
|
|
|
var params = {};
|
|
params["getNodeDetails"] = 1;
|
|
params["id_node_data"] = data_id;
|
|
params["data_graph_id"] = data_graph_id;
|
|
params["node_id"] = node_id;
|
|
params["page"] = "include/ajax/map.ajax";
|
|
|
|
jQuery.ajax ({
|
|
data: params,
|
|
dataType: "JSON",
|
|
type: "POST",
|
|
url: "ajax.php",
|
|
success: function (data) {
|
|
var window_popup = window.open("", "window_" + data_graph_id,
|
|
'title=DETAILS, width=300, height=300, toolbar=no, location=no, directories=no, status=no, menubar=no');
|
|
|
|
$(window_popup.document.body).html(data);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function editNode
|
|
* Return void
|
|
* This function prints the node edition table
|
|
*/
|
|
MapController.prototype.editNode = function(self, target) {
|
|
}
|
|
|
|
/**
|
|
* Function deleteNode
|
|
* Return void
|
|
* This function delete a node and the arrows that use it
|
|
*/
|
|
MapController.prototype.deleteNode = function(self, target) {
|
|
var self = this;
|
|
|
|
$.each(self.get_nodes_map(), function(i, node) {
|
|
if (!self.is_delety(node))
|
|
return 1; // Continue
|
|
|
|
var status_selection =
|
|
self.get_status_selection_node(node.graph_id);
|
|
|
|
if (status_selection.indexOf("select") == -1) {
|
|
return 1; // Continue
|
|
}
|
|
|
|
var id_node = "node_" + node.graph_id;
|
|
|
|
var arrowsToDelete = self.get_edges_to_del(node.graph_id);
|
|
|
|
// Delete edges and nodes in "nodes" and "edges" arrays
|
|
self.deleteEdgesAndNode(arrowsToDelete, id_node);
|
|
|
|
// Delete visual edges and nodes
|
|
arrowsToDelete.forEach(function(arrow) {
|
|
d3.select("#arrow_" + arrow['graph_id']).remove();
|
|
});
|
|
|
|
d3.select(self._target + " #" + id_node).remove();
|
|
d3.select(self._target + " .minimap" + " #" + id_node).remove();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Function deleteEdges
|
|
* Return void
|
|
* This function delete the edges of a node in the edges array
|
|
*/
|
|
MapController.prototype.deleteEdgesAndNode = function(arrowsToDelete, id_node) {
|
|
var self = this;
|
|
var temp;
|
|
|
|
arrowsToDelete.forEach(function(arrow) {
|
|
temp = [];
|
|
self.get_edges_map().forEach(function(edge) {
|
|
if (edge["graph_id"] != arrow['graph_id']) {
|
|
temp.push(edge);
|
|
}
|
|
});
|
|
self.set_edges_map(temp);
|
|
});
|
|
|
|
arrowsToDelete.forEach(function(arrow) {
|
|
temp = [];
|
|
self.get_nodes_map().forEach(function(nodeOrEdge) {
|
|
var nodeToDel = "node_" + nodeOrEdge["graph_id"];
|
|
|
|
if ((nodeOrEdge["graph_id"] != arrow['graph_id']) && (nodeToDel != id_node)) {
|
|
temp.push(nodeOrEdge);
|
|
}
|
|
});
|
|
self.set_nodes_map(temp);
|
|
});
|
|
|
|
if (arrowsToDelete.length == 0) {
|
|
temp = [];
|
|
self.get_nodes_map().forEach(function(nodeOrEdge) {
|
|
var nodeToDel = "node_" + nodeOrEdge["graph_id"];
|
|
|
|
if (nodeToDel != id_node) {
|
|
temp.push(nodeOrEdge);
|
|
}
|
|
});
|
|
self.set_nodes_map(temp);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function get_edges_to_del
|
|
* Return array[edge]
|
|
* This function returns the edges of a node to delete them
|
|
*/
|
|
MapController.prototype.get_edges_to_del = function(id_graph) {
|
|
var self = this;
|
|
|
|
var return_edges = [];
|
|
|
|
$.each(self.get_edges_map(), function(i, edge) {
|
|
if ((edge['to']['graph_id'] == id_graph) || (edge['from']['graph_id'] == id_graph)) {
|
|
return_edges.push(edge);
|
|
}
|
|
});
|
|
|
|
return return_edges;
|
|
}
|
|
|
|
/**
|
|
* Function getArrows
|
|
* Return array[id_arrow]
|
|
* This function returns the arrows of a node
|
|
*/
|
|
MapController.prototype.getArrows = function(id_node) {
|
|
var self = this;
|
|
|
|
var edgesToDel = [];
|
|
var j = 0;
|
|
|
|
self.get_edges_map().forEach(function(edge, index) {
|
|
var nodeTo = "node_" + edge["to"];
|
|
var nodeFrom = "node_" + edge["from"];
|
|
if (nodeTo == id_node || nodeFrom == id_node) {
|
|
edgesToDel[index] = edge["graph_id"];
|
|
}
|
|
});
|
|
|
|
return edgesToDel;
|
|
}
|
|
|
|
/**
|
|
* Function close_all_tooltips
|
|
* Return void
|
|
* This function hide nodes tooltips
|
|
*/
|
|
MapController.prototype.close_all_tooltips = function() {
|
|
$("svg .tooltipstered").tooltipster("destroy");
|
|
}
|
|
|
|
/**
|
|
* Function nodeData
|
|
* Return array(data)
|
|
* This function returns the data of the node
|
|
*/
|
|
MapController.prototype.nodeData = function(data_id, type, id_map, data_graph_id, origin, node_id) {
|
|
var params = {};
|
|
params["getNodeData"] = 1;
|
|
params["id_node_data"] = data_id;
|
|
params["type"] = type;
|
|
params["id_map"] = id_map;
|
|
params["data_graph_id"] = data_graph_id;
|
|
params["node_id"] = node_id;
|
|
params["page"] = "include/ajax/map.ajax";
|
|
|
|
jQuery.ajax ({
|
|
data: params,
|
|
dataType: "json",
|
|
type: "POST",
|
|
url: "ajax.php",
|
|
success: function (data) {
|
|
if ($(origin).hasClass("tooltipstered")) {
|
|
origin.tooltipster('content', data);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* Function arrow_by_pieces
|
|
* Return void
|
|
* This function print the arrow by pieces (3 steps)
|
|
*/
|
|
//~ MapController.prototype.arrow_by_pieces = function(target, id_arrow, id_node_to, id_node_from, wait) {
|
|
MapController.prototype.arrow_by_pieces = function(target, arrow_data, wait) {
|
|
var self = this;
|
|
|
|
if (typeof(wait) === "undefined")
|
|
wait = 1;
|
|
|
|
var count_files = 2;
|
|
function wait_load(callback) {
|
|
count_files--;
|
|
|
|
if (count_files == 0) {
|
|
callback();
|
|
}
|
|
}
|
|
|
|
var arrow_layout = d3
|
|
.select(target + " #arrow_" + arrow_data['graph_id']);
|
|
|
|
switch (wait) {
|
|
/*---------------------------------------------*/
|
|
/*-------- Preload head and body arrow --------*/
|
|
/*---------------------------------------------*/
|
|
case 1:
|
|
arrow_layout = arrow_layout.append("g")
|
|
.attr("class", "arrow_position_rotation")
|
|
.append("g")
|
|
.attr("class", "arrow_translation")
|
|
.append("g")
|
|
.attr("class", "arrow_container");
|
|
|
|
if (is_buggy_firefox) {
|
|
arrow_layout.append("g")
|
|
.attr("class", "body")
|
|
.append("use")
|
|
.attr("xlink:href", "#body_arrow");
|
|
|
|
arrow_layout.append("g")
|
|
.attr("class", "head")
|
|
.append("use")
|
|
.attr("xlink:href", "#head_arrow");
|
|
|
|
self.arrow_by_pieces(target, arrow_data, 0);
|
|
}
|
|
else {
|
|
arrow_layout.append("g")
|
|
.attr("class", "body")
|
|
.append("use")
|
|
.attr("xlink:href", "images/maps/body_arrow.svg#body_arrow")
|
|
.on("load", function() {
|
|
wait_load(function() {
|
|
self.arrow_by_pieces(target, arrow_data, 0);
|
|
});
|
|
});
|
|
|
|
arrow_layout.append("g")
|
|
.attr("class", "head")
|
|
.append("use")
|
|
.attr("xlink:href", "images/maps/head_arrow.svg#head_arrow")
|
|
.on("load", function() {
|
|
wait_load(function() {
|
|
self.arrow_by_pieces(target, arrow_data, 0);
|
|
});
|
|
});
|
|
}
|
|
break;
|
|
/*---------------------------------------------*/
|
|
/*---- Print head and body arrow by steps -----*/
|
|
/*---------------------------------------------*/
|
|
case 0:
|
|
if (arrow_data['temp']) {
|
|
switch (arrow_data['type']) {
|
|
case 'parent':
|
|
var id_node_to = null;
|
|
var id_node_from = "node_" + arrow_data['from']['graph_id'];
|
|
|
|
var c_elem2 = arrow_data['mouse'];
|
|
var c_elem1 = get_center_element(self._target +" #" + id_node_from);
|
|
|
|
var radius_to = 5;
|
|
var radius_from = parseFloat(get_radius_element("#" + id_node_from));
|
|
break;
|
|
case 'children':
|
|
var id_node_to = "node_" + arrow_data['to']['graph_id'];
|
|
var id_node_from = null;
|
|
|
|
var c_elem2 = get_center_element(self._target +" #" + id_node_to);
|
|
var c_elem1 = arrow_data['mouse'];
|
|
|
|
var radius_to = parseFloat(get_radius_element("#" + id_node_to));
|
|
var radius_from = 5;
|
|
break;
|
|
}
|
|
|
|
}
|
|
else {
|
|
var id_node_to = "node_" + arrow_data['to']['graph_id'];
|
|
var id_node_from = "node_" + arrow_data['from']['graph_id'];
|
|
|
|
var c_elem2 = get_center_element(self._target +" #" + id_node_to);
|
|
var c_elem1 = get_center_element(self._target +" #" + id_node_from);
|
|
|
|
var radius_to = parseFloat(get_radius_element("#" + id_node_to));
|
|
var radius_from = parseFloat(get_radius_element("#" + id_node_from));
|
|
}
|
|
|
|
var distance = get_distance_between_point(c_elem1, c_elem2);
|
|
|
|
var transform = d3.transform();
|
|
|
|
/*---------------------------------------------*/
|
|
/*--- Position of layer arrow (body + head) ---*/
|
|
/*---------------------------------------------*/
|
|
var arrow_body = arrow_layout.select(".body");
|
|
var arrow_body_b = arrow_body.node().getBBox();
|
|
var arrow_body_height = (arrow_body_b['height'] + arrow_body_b['y']);
|
|
var arrow_body_width = (arrow_body_b['width'] + arrow_body_b['x']);
|
|
|
|
transform.translate[0] = c_elem1[0];
|
|
transform.translate[1] = c_elem1[1];
|
|
transform.rotate = get_angle_of_line(c_elem1, c_elem2);
|
|
|
|
arrow_layout.select(".arrow_position_rotation").attr("transform", transform.toString());
|
|
transform = d3.transform();
|
|
transform.translate[0] = radius_from;
|
|
transform.translate[1] = - (arrow_body_height / 2);
|
|
arrow_layout.select(".arrow_translation").attr("transform", transform.toString());
|
|
|
|
/*---------------------------------------------*/
|
|
/*-------- Resize the body arrow width --------*/
|
|
/*---------------------------------------------*/
|
|
var arrow_head = arrow_layout.select(".head");
|
|
var arrow_head_b = arrow_head.node().getBBox();
|
|
var arrow_head_height = (arrow_head_b['height'] + arrow_head_b['y']);
|
|
var arrow_head_width = (arrow_head_b['width'] + arrow_head_b['x']);
|
|
|
|
var body_width = distance - arrow_head_width - radius_to - radius_from;
|
|
|
|
transform = d3.transform();
|
|
transform.scale[0] = body_width / arrow_body_width;
|
|
|
|
arrow_body.attr("transform", transform.toString());
|
|
|
|
/*---------------------------------------------*/
|
|
/*---------- Position of head arrow -----------*/
|
|
/*---------------------------------------------*/
|
|
transform = d3.transform();
|
|
|
|
var arrow_body_t = d3.transform(arrow_body.attr("transform"));
|
|
|
|
var scale = arrow_body_t.scale[0];
|
|
var x = 0 + arrow_body_width * scale;
|
|
var y = 0 + (arrow_body_height / 2 - arrow_head_height / 2);
|
|
|
|
transform.translate[0] = x;
|
|
transform.translate[1] = y;
|
|
|
|
arrow_head.attr("transform", transform.toString());
|
|
|
|
/*---------------------------------------------*/
|
|
/*------- Show the result in one time ---------*/
|
|
/*---------------------------------------------*/
|
|
arrow_layout.attr("style", "opacity: 1");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------*/
|
|
/*-------------------Functions-------------------*/
|
|
/*-----------------------------------------------*/
|
|
/**
|
|
* Function open_in_another_window
|
|
* Return void
|
|
* This function open the node in extra window
|
|
*/
|
|
function open_in_another_window(link) {
|
|
window.open(link);
|
|
}
|
|
|
|
/**
|
|
* Function close_button_tooltip
|
|
* Return void
|
|
* This function manages "close" button from tooltips
|
|
*/
|
|
function close_button_tooltip(data_graph_id) {
|
|
$("#node_" + data_graph_id).tooltipster("destroy");
|
|
}
|
|
|
|
/**
|
|
* Function tooltip_to_new_window
|
|
* Return void
|
|
* This function manages "open in new wondow" button from tooltips
|
|
*/
|
|
function tooltip_to_new_window(data_graph_id) {
|
|
var content = $("#tooltip_" + data_graph_id + " .body").html();
|
|
|
|
$("#node_" + data_graph_id).tooltipster("destroy");
|
|
|
|
var window_popup = window.open("", "window_" + data_graph_id,
|
|
'title=NEW_WINDOW, width=300, height=300, toolbar=no, location=no, directories=no, status=no, menubar=no');
|
|
|
|
$(window_popup.document.body).html(content);
|
|
}
|
|
|
|
/**
|
|
* Function get_distance_between_point
|
|
* Return float
|
|
* This function returns the distance between two nodes
|
|
*/
|
|
function get_distance_between_point(point1, point2) {
|
|
var delta_x = Math.abs(point1[0] - point2[0]);
|
|
var delta_y = Math.abs(point1[1] - point2[1]);
|
|
|
|
return Math.sqrt(
|
|
Math.pow(delta_x, 2) + Math.pow(delta_y, 2));
|
|
}
|
|
|
|
/**
|
|
* Function get_center_element
|
|
* Return array[x, y]
|
|
* This function returns the center of the node
|
|
*/
|
|
function get_center_element(element) {
|
|
var element_t;
|
|
try {
|
|
element_t = d3.transform(d3.select(element).attr("transform"));
|
|
}
|
|
catch(err) {
|
|
console.log(element, err);
|
|
}
|
|
//~ var element_t = d3.transform(d3.select(element).attr("transform"));
|
|
var element_t_scale = parseFloat(element_t['scale']);
|
|
var element_b = d3.select(element).node().getBBox();
|
|
|
|
var box_x = parseFloat(element_t.translate[0]) +
|
|
parseFloat(element_b['x']) * element_t_scale;
|
|
var box_y = parseFloat(element_t.translate[1]) +
|
|
parseFloat(element_b['y']) * element_t_scale;
|
|
|
|
var width = (element_t_scale * element_b['width']);
|
|
var height = (element_t_scale * element_b['height']);
|
|
|
|
var c_x = box_x + (width / 2);
|
|
var c_y = box_y + (height / 2);
|
|
|
|
return [c_x, c_y];
|
|
}
|
|
|
|
/**
|
|
* Function get_angle_of_line
|
|
* Return float
|
|
* This function returns the angle between two lines (center node to another node)
|
|
*/
|
|
function get_angle_of_line(point1, point2) {
|
|
return Math.atan2(point2[1] - point1[1], point2[0] - point1[0]) * 180 / Math.PI;
|
|
}
|
|
|
|
/**
|
|
* Function getBBox_Symbol
|
|
* Return BBox
|
|
* This function returns bbox of the symbol
|
|
*/
|
|
function getBBox_Symbol(target, symbol) {
|
|
var base64symbol = btoa(symbol).replace(/=/g, "");
|
|
|
|
return d3.select(target + " #" + base64symbol).node().getBBox();
|
|
}
|
|
|
|
/**
|
|
* Function get_size_element
|
|
* Return array[width, height]
|
|
* This function returns the size of the element
|
|
*/
|
|
function get_size_element(element) {
|
|
var transform = d3.transform(d3.select(element).attr("transform"));
|
|
var element_b = d3.select(element).node().getBBox();
|
|
|
|
|
|
return [
|
|
element_b['width'] * transform.scale[0],
|
|
element_b['height'] * transform.scale[1]];
|
|
}
|
|
|
|
/**
|
|
* Function get_radius_element
|
|
* Return void
|
|
* This function returns the element radius
|
|
*/
|
|
function get_radius_element(element) {
|
|
// Hack for the circle items
|
|
if (!d3.select(element + " .layout_size_node circle").empty()) {
|
|
return parseFloat(
|
|
d3.select(element + " .layout_size_node circle").attr("r"));
|
|
}
|
|
else {
|
|
//~ var size = get_size_element(element);
|
|
var size = get_size_element(element + " .layout_size_node");
|
|
|
|
return Math.sqrt(
|
|
Math.pow(size[0] / 2, 2) + Math.pow(size[1] / 2, 2));
|
|
}
|
|
}
|