', {
class: [Init.classes.pieChart.class, Init.classes.pieChart.pieChartMapCounterClass].join(' ')
}).attr('data-percent', percent).append(
$('
', {
text: value
})
);
mapOverlay.append(counterChart);
// init counter
counterChart.initMapUpdateCounter();
// set tooltip
mapOverlay.attr('data-toggle', 'tooltip');
mapOverlay.attr('data-placement', 'left');
mapOverlay.attr('title', 'update counter');
mapOverlay.tooltip();
}
return counterChart;
};
/**
* start the map update counter or reset
*/
$.fn.startMapUpdateCounter = function(){
var mapOverlay = $(this);
var counterChart = mapOverlay.getMapCounter();
var seconds = 10;
// get counter interval (in case there is an active one)
var interval = counterChart.data('interval');
if(interval){
clearInterval(interval);
}
mapOverlay.fadeIn(200);
var counterChartLabel = counterChart.find('span');
var percentPerCount = 100 / seconds;
var timer = function(){
seconds--;
counterChart.data('easyPieChart').update( percentPerCount * seconds);
counterChartLabel.text(seconds);
if(seconds <= 0){
clearInterval(mapUpdateCounter);
setTimeout(function(){
mapOverlay.fadeOut(200);
counterChart.data('interval', false);
}, 800);
return;
}
};
// start timer
var mapUpdateCounter = setInterval(timer, 1000);
counterChart.data('easyPieChart').update( percentPerCount * seconds);
counterChartLabel.text(seconds);
// store counter
counterChart.data('interval', mapUpdateCounter);
};
/**
* update z-index for a system (dragged sytems should be always on top)
* @param system
*/
var updateZIndex = function(system){
var newZIndexSystem = config.zIndexCounter++;
$(system).css('z-index', newZIndexSystem);
};
/**
* get all connections of multiple systems
* @param map
* @param systems Array of Systems objectts
* @returns {Array} of all connections
*/
var getConnections = function(map, systems){
var connections = [];
$.each(systems, function(i, system){
// get connections where system is source
connections = connections.concat( map.getConnections({source: system}) );
// get connections where system is target
connections = connections.concat( map.getConnections({target: system}) );
});
return connections;
};
/**
* get all direct connections between two given systems
* @param map
* @param systemA
* @param systemB
* @returns {Array}
*/
var checkForConnection = function(map, systemA, systemB){
var connections = [];
connections = connections.concat( map.getConnections({source: systemA, target: systemB}) );
// getconnections where system is target
connections = connections.concat( map.getConnections({source: systemB, target: systemA}) );
return connections;
};
/**
* connect two systems
* @param mapConfig
* @param connectionData
* @returns new connection
*/
var drawConnection = function(map, connectionData){
var connection = map.connect({
source: config.systemIdPrefix + connectionData.source,
target: config.systemIdPrefix + connectionData.target,
type: connectionData.type
/* experimental (straight connections)
anchors: [
[ "Perimeter", { shape: 'Rectangle' }],
[ "Perimeter", { shape: 'Rectangle' }]
]
*/
});
// set Observer for new Connection
setConnectionObserver(map, connection);
return connection;
};
/**
* load context menu template for map
*/
var initMapContextMenu = function(){
var moduleConfig = {
name: 'modules/contextmenu',
position: $('#' + config.dynamicElementWrapperId)
};
var moduleData = {
id: config.mapContextMenuId,
items: [
{icon: 'fa-plus', action: 'add_system', text: 'add system'},
{icon: 'fa-info', action: 'info', text: 'info'},
{divider: true},
{icon: 'fa-eraser', action: 'delete_systems', text: 'delete systems'}
]
};
Render.showModule(moduleConfig, moduleData);
};
/**
* load contextmenu template for connections
*/
var initConnectionContextMenu = function(){
var moduleConfig = {
name: 'modules/contextmenu',
position: $('#' + config.dynamicElementWrapperId)
};
var moduleData = {
id: config.connectionContextMenuId,
items: [
{icon: 'fa-info', action: 'info', text: 'info'},
{icon: 'fa-plane', action: 'frigate', text: 'frigate hole'},
{icon: 'fa-warning', action: 'preserve_mass', text: 'preserve mass'},
{icon: 'fa-reply fa-rotate-180', text: 'change status', subitems: [
{subIcon: 'fa-clock-o', subAction: 'eol', subText: 'toggle EOL'},
{subDivider: true},
{subIcon: 'fa-circle', subAction: 'status_fresh', subText: 'stage 0 (fresh)'},
{subIcon: 'fa-adjust', subAction: 'status_reduced', subText: 'stage 1 (reduced)'},
{subIcon: 'fa-circle-o', subAction: 'status_critical', subText: 'stage 2 (critical)'}
]},
{divider: true},
{icon: 'fa-eraser', action: 'delete', text: 'delete'}
]
};
Render.showModule(moduleConfig, moduleData);
};
/**
* load contextmenu template for systems
*/
var initSystemContextMenu = function(){
var systemStatus = [];
$.each(Init.classes.systemStatus, function(status, statusData){
var tempStatus = {
subIcon: 'fa-circle',
subIconClass: statusData.class,
subAction: 'change_status_' + status,
subText: statusData.label
};
systemStatus.push(tempStatus);
});
var moduleConfig = {
name: 'modules/contextmenu',
position: $('#' + config.dynamicElementWrapperId)
};
var moduleData = {
id: config.systemContextMenuId,
items: [
{icon: 'fa-plus', action: 'add_system', text: 'add system'},
{icon: 'fa-lock', action: 'lock_system', text: 'lock system'},
{icon: 'fa-users', action: 'set_rally', text: 'set rally point'},
{icon: 'fa-reply fa-rotate-180', text: 'change status', subitems: systemStatus},
{divider: true},
{icon: 'fa-eraser', action: 'delete_system', text: 'delete system'}
]
};
Render.showModule(moduleConfig, moduleData);
};
/**
* set up context menu for all Systems within a given map
* @param endpoints
*/
var setSystemObserver = function(map, system){
system = $(system);
var systemHeadExpand = $( system.find('.' + config.systemHeadExpandClass) );
var systemBody = $( system.find('.' + config.systemBodyClass) );
var bodyItemheight = 16;
// init system tooltips ================================================================
var systemTooltipOptions = {
toggle: 'tooltip',
placement: 'right',
viewport: system.id
};
system.find('.fa').tooltip(systemTooltipOptions);
// init system body expand ============================================================
systemHeadExpand.hoverIntent(function(e){
// hover in
var hoverSystem = $(this).parents('.' + config.systemClass);
// get ship counter and calculate expand height
var shipCounter = parseInt( system.attr('data-original-title') );
var expandheight = shipCounter * bodyItemheight;
systemBody.animate(
{
height: expandheight + 'px',
width: '100%',
'min-width': '150px'
},
{
// queue:false,
duration: 100,
step: function(){
// repaint connections of current system
map.repaint( hoverSystem );
},
complete: function(){
map.repaint( hoverSystem );
$(this).find('.' + config.systemBodyRightClass).show();
}
}
);
}, function(e){
// hover out
var hoverSystem = $(this).parents('.' + config.systemClass);
systemBody.animate(
{
height: '16px',
width: '100%',
'min-width': '80px'
},
{
// queue:false,
duration: 100,
step: function(){
// repaint connections of current system
map.repaint( hoverSystem );
$(this).find('.' + config.systemBodyRightClass).hide();
},
start: function(){
$(this).find('.' + config.systemBodyRightClass).hide();
},
complete: function(){
map.repaint( hoverSystem );
}
}
);
});
// context menu ==================================================================
// trigger context menu
system.on('contextmenu', function(e){
// hide all map tooltips
$(e.target).trigger('pf:openContextMenu', [e, this]);
e.preventDefault();
return false;
});
// init context menu
system.contextMenu({
menuSelector: "#" + config.systemContextMenuId,
menuSelected: function (params) {
// click action
var action = params.selectedMenu.attr('data-action');
// current system
var currentSystem = $(params.component);
// system name
var currentSystemName = currentSystem.getSystemInfo( ['name'] );
switch(action){
case 'add_system':
// add a new system
showNewSystemDialog(map, {sourceSystem: currentSystem} );
break;
case 'lock_system':
// lock system
currentSystem.toggleLockSystem(true, {map: map});
// repaint connections, -> system changed its size!
map.repaint( currentSystem );
break;
case 'set_rally':
// set rally point
if( ! currentSystem.data( 'rally' ) ){
// show confirm dialog
var rallyDialog = bootbox.dialog({
message: 'Do you want to poke active pilots?',
title: 'Set rally point for system "' + currentSystemName + '"',
buttons: {
close: {
label: 'cancel',
className: 'btn-default',
callback: function(){
$(rallyDialog).modal('hide');
}
},
setRallyPoke: {
label: ' Set rally and poke',
className: 'btn-info',
callback: function() {
currentSystem.toggleRallyPoint(true, {});
}
},
setRallay: {
label: ' Set rally',
className: 'btn-primary',
callback: function() {
currentSystem.toggleRallyPoint(false, {});
}
}
}
});
}else{
// remove rally point
currentSystem.toggleRallyPoint(false, {});
}
break;
case 'change_status_unknown':
case 'change_status_friendly':
case 'change_status_occupied':
case 'change_status_hostile':
case 'change_status_empty':
case 'change_status_unscanned':
$(currentSystem).getMapOverlay().startMapUpdateCounter();
// remove all status classes from system
$.each(Init.classes.systemStatus, function(status, statusData){
currentSystem.removeClass( statusData.class );
});
// add new class
var statusString = action.split('_');
var statusClass = Util.getStatusInfoForSystem(statusString[2], 'class');
var statusLabel = Util.getStatusInfoForSystem(statusString[2], 'label');
currentSystem.data('status', statusLabel);
currentSystem.addClass( statusClass );
break;
case 'delete_system':
// confirm dialog
bootbox.confirm('Delete system and all its connections?', function(result) {
if(result){
$(currentSystem).getMapOverlay().startMapUpdateCounter();
var systemName = currentSystem.getSystemInfo(['name']);
deleteSystem(map, currentSystem);
Util.showNotify({title: 'System deleted', text: systemName, type: 'success'});
}
});
break;
}
}
});
// load system data =================================================================================
system.on('click', function(e){
var system = $(this);
if(e.which === 1){
// left mouse button
if(e.ctrlKey === true){
// select system
system.toggleSelectSystem(map);
}else{
// activate system
markSystemActive(map, system);
// get parent Tab Content and fire update event
var tabContentElement = getTabContentElementByMapElement( system );
var data = {
system: system
};
$(tabContentElement).trigger('pf:updateSystemData', [data]);
}
}
});
};
/**
* toggle select status of a system
*/
$.fn.toggleSelectSystem = function(map){
var system = $(this);
var mapElement = system.parent();
if( system.data('locked') !== true ){
if( system.hasClass( config.systemSelectedClass ) ){
system.removeClass( config.systemSelectedClass );
// set single draggable for this system
system.multiDraggable({map: map, group: system});
}else{
system.addClass( config.systemSelectedClass );
}
// there can still be multiple selected systems :)
var selectedSystems = $(mapElement).getSelectedSystems();
if(selectedSystems.length > 0){
$(selectedSystems).multiDraggable({map: map, group: selectedSystems});
}
}else{
var systemName = system.getSystemInfo( ['name'] );
Util.showNotify({title: 'System is locked', text: systemName, type: 'error'});
}
};
/**
* get all selected (NOT active) systems in a map
* @returns {*}
*/
$.fn.getSelectedSystems = function(){
var mapElement = $(this);
var systems = mapElement.find('.' + config.systemSelectedClass);
return systems;
};
/**
* toggle log status of a system
* @param poke
* @param options
*/
$.fn.toggleLockSystem = function(poke, options){
var system = $(this);
var map = options.map;
var hideNotification = false;
if(options.hideNotification === true){
hideNotification = true;
}
var hideCounter = false;
if(options.hideCounter === true){
hideCounter = true;
}
var systemName = system.getSystemInfo( ['name'] );
if( system.data( 'locked' ) === true ){
system.data('locked', false);
system.removeClass( config.systemLockedClass );
// set draggable capability
system.multiDraggable({map: map, group: system});
if(! hideNotification){
Util.showNotify({title: 'System lock removed', text: 'System: ' + systemName, type: 'success'});
}
}else{
system.data('locked', true);
system.addClass( config.systemLockedClass );
// remove draggable capability
system.destroySystemDraggable();
if(! hideNotification){
Util.showNotify({title: 'System is locked', text: 'System: ' + systemName, type: 'success'});
}
}
if(! hideCounter){
$(system).getMapOverlay().startMapUpdateCounter();
}
};
/**
* toggle a system as rally point and display notifications
* @param poke
* @param options
*/
$.fn.toggleRallyPoint = function(poke, options){
var system = $(this);
var rallyClass = Util.getInfoForSystem('rally', 'class');
var hideNotification = false;
if(options.hideNotification === true){
hideNotification = true;
}
var hideCounter = false;
if(options.hideCounter === true){
hideCounter = true;
}
// check of system is already marked as rally
if( system.data( 'rally' ) === true ){
system.removeClass( rallyClass );
system.data( 'rally', false );
if(! hideNotification){
Util.showNotify({title: 'Rally point removed', type: 'success'});
}
}else{
system.addClass( rallyClass );
system.data( 'rally', true );
if(! hideNotification){
var systemName = system.getSystemInfo( ['name'] );
var notificationOptions = {
title: 'New rally Point',
text: 'System: ' + systemName,
type: 'success'
};
if(poke === true){
// desktop poke
Util.showNotify(notificationOptions, {desktop: true, stack: 'barBottom'});
}else{
Util.showNotify(notificationOptions, {stack: 'barBottom'});
}
}
}
if(! hideCounter){
$(system).getMapOverlay().startMapUpdateCounter();
}
};
/**
* get all TabContentElements
* @returns {*|HTMLElement}
*/
var getTabContentElements = function(){
return $('.' + config.mapTabContentClass);
};
/**
* get TabContentElement by any element on a map e.g. system
* @param element
* @returns {*}
*/
var getTabContentElementByMapElement = function(element){
var tabContentElement = $(element).parents('.' + config.mapTabContentClass);
return tabContentElement;
};
/**
* set observer for a map container
* @param map
*/
var setMapObserver = function(map){
// get map container
var container = map.getContainer();
$(container).on('contextmenu', function(e){
$(e.target).trigger('pf:openContextMenu', [e, this]);
e.preventDefault();
e.stopPropagation();
return false;
});
$(container).contextMenu({
menuSelector: "#" + config.mapContextMenuId,
menuSelected: function (params) {
// click action
var action = params.selectedMenu.attr('data-action');
// current map
var currentMapElement = $(params.component);
var currentMapId = parseInt( currentMapElement.data('id') );
// get map instance
var currentMap = getMapInstance(currentMapId);
// click position
var position = params.position;
switch(action){
case 'add_system':
// add new system dialog
showNewSystemDialog(currentMap, {position: position});
break;
case 'delete_systems':
// delete all selected systems with its connections
var selectedSystems = $(currentMapElement).getSelectedSystems();
if(selectedSystems.length > 0){
bootbox.confirm('Delete ' + selectedSystems.length + ' selected systems and its connections?', function(result) {
if(result){
for(var i = 0; i < selectedSystems.length; i++){
deleteSystem(currentMap, selectedSystems[i]);
}
Util.showNotify({title: selectedSystems.length + ' systems deleted', type: 'success'});
}
});
}else{
Util.showNotify({title: 'No systems selected', type: 'error'});
}
break;
}
}
});
// init drag-frame selection
$(container).dragToSelect({
selectables: '.' + config.systemClass,
onHide: function (selectBox, deselectedSystems) {
var selectedSystems = $(container).getSelectedSystems();
if(selectedSystems.length > 0){
// make all selected systems draggable
Util.showNotify({title: selectedSystems.length + ' systems selected', type: 'success'});
$(selectedSystems).multiDraggable({map: map, group: selectedSystems});
}
// convert former group draggable systems so single draggable
for(var i = 0; i < deselectedSystems.length; i++){
$(deselectedSystems[i]).multiDraggable({map: map, group: deselectedSystems[i]});
}
},
onShow: function(){
},
onRefresh: function(){
}
});
// catch menu events ====================================================
// toggle "snap to grid" option
$(container).on('pf:menuGrid', function(e, data){
config.mapSnapToGrid = !config.mapSnapToGrid;
// toggle grid class
$(this).toggleClass(config.mapGridClass);
// toggle button class
$(data.button).toggleClass('active');
var notificationText = 'disabled';
if(config.mapSnapToGrid){
notificationText = 'enabled';
}
Util.showNotify({title: 'Grid snapping', text: notificationText, type: 'info'});
});
};
/**
* set observer for a given connection
* @param map
* @param connection
*/
var setConnectionObserver = function(map, connection){
connection.bind('contextmenu', function(component, e) {
// trigger menu "open
$(e.target).trigger('pf:openContextMenu', [e, component]);
e.preventDefault();
e.stopPropagation();
return false;
});
/**
* init context menu for all connections
* must be triggered manually on demand
*/
$('path').contextMenu({
menuSelector: "#" + config.connectionContextMenuId,
menuSelected: function (params){
var action = params.selectedMenu.attr('data-action');
var activeConnection = params.component;
switch(action){
case 'delete':
// delete a single connection
// confirm dialog
bootbox.confirm('Is this connection really gone?', function(result) {
if(result){
map.detach(params.component);
}
});
break;
case 'frigate': // set as frigate hole
case 'preserve_mass': // set "preserve mass
case 'eol': // set "end of life"
activeConnection.toggleType( action );
// for some reason a new observer is needed ?!
setConnectionObserver(map, activeConnection);
break;
case 'status_fresh':
activeConnection.removeType('wh_reduced');
activeConnection.removeType('wh_critical');
setConnectionObserver(map, activeConnection);
break;
case 'status_reduced':
activeConnection.removeType('wh_critical');
activeConnection.addType('wh_reduced');
setConnectionObserver(map, activeConnection);
break;
case 'status_critical':
activeConnection.removeType('wh_reduced');
activeConnection.addType('wh_critical');
setConnectionObserver(map, activeConnection);
break;
case 'info':
console.log('info');
break;
}
}
});
};
/**
* mark a system as active
* @param map
* @param system
*/
var markSystemActive = function(map, system){
// deactivate all systems in map
var mapContainer = $( map.getContainer() );
mapContainer.find('.' + config.systemClass).removeClass(config.systemActiveClass);
// set current system active
system.addClass(config.systemActiveClass);
};
/**
* get system data out of its object
* @param info
* @returns {*}
*/
$.fn.getSystemInfo = function(info){
var systemInfo = [];
for(var i = 0; i < info.length; i++){
switch(info[i]){
case 'name':
// get current system name/alias
systemInfo.push( $(this).find('.' + config.systemHeadNameClass).text() );
break;
default:
systemInfo.push('bad system query');
}
}
if(systemInfo.length === 1){
return systemInfo[0];
}else{
return systemInfo;
}
};
/**
* open "new system" dialog and add the system to map
* optional the new system is connected to a "sourceSystem" (if available)
*
* @param map
* @param options
*/
var showNewSystemDialog = function(map, options){
// format system status for form select
var systemStatus = {};
$.each(Init.classes.systemStatus, function(status, statusData){
//statusData.status = status;
//systemStatus.push(statusData);
systemStatus[status] = statusData.label;
});
var data = {
id: config.systemDialogId,
system: 'lalala',
status: systemStatus
};
requirejs(['text!templates/modules/system_dialog.html', 'lib/mustache'], function(template, Mustache) {
var content = Mustache.render(template, data);
var systemDialog = bootbox.dialog({
title: 'Add new system',
message: content,
buttons: {
close: {
label: 'cancel',
className: 'btn-default',
callback: function(){
$(systemDialog).modal('hide');
}
},
success: {
label: 'Add system',
className: 'btn-primary',
callback: function () {
$(options.sourceSystem).getMapOverlay().startMapUpdateCounter();
// get form Values
var form = $('#' + config.systemDialogId).find('form');
var newSystemData = $(form).getFormValues();
var currentX = 0;
var currentY = 0;
var newPositon = {
x: 0,
y: 0
};
var sourceSystem = null;
// add new position
if(options.sourceSystem !== undefined){
sourceSystem = options.sourceSystem;
// related system is available
currentX = sourceSystem.css('left');
currentY = sourceSystem.css('top');
// remove "px"
currentX = parseInt( currentX.substring(0, currentX.length - 2) );
currentY = parseInt( currentY.substring(0, currentY.length - 2) );
newPositon = {
x: currentX + config.newSystemOffset.x,
y: currentY + config.newSystemOffset.y
};
}else{
// check mouse cursor position (add system to map)
newPositon = {
x: options.position.x,
y: options.position.y
};
}
newSystemData.position = newPositon;
// draw new system to map
drawSystem(map, newSystemData, sourceSystem);
}
}
}
}
);
// make dialog editable
var modalFields = $('.bootbox .modal-dialog').find('.pf-editable-system-status');
modalFields.editable({
mode: 'inline',
emptytext: 'unknown',
onblur: 'submit',
source: systemStatus
});
});
};
var getMapInstance = function(mapId){
if(typeof activeInstances[mapId] !== 'object'){
// create new instance
activeInstances[mapId] = jsPlumb.getInstance({
Container: null, // will be set as soon as container is connected to DOM
PaintStyle:{
lineWidth: 4, // width of a Connector's line. An integer.
strokeStyle: 'red', // color for a Connector
outlineColor: 'red', // color of the outline for an Endpoint or Connector. see fillStyle examples.
outlineWidth: 2 // width of the outline for an Endpoint or Connector. An integer.
},
Connector:[ 'Bezier', { curviness: 40, cssClass: 'pf-map-connection-wh' } ],
Endpoint : ['Dot', {radius: 6}]
// Endpoint: 'Blank', // does not work... :(
// Scope: mapConfig.config.scope
});
console.log('new jsPlumbInstance: ' + mapId);
}
return activeInstances[mapId];
};
/**
* updates all systems on map with current user Data (all users on this map)
* update the Data of the user that is currently viewing the map (if available) -> In - game info
* @param userData
* @param currentUserData
*/
$.fn.updateUserData = function(userData, currentUserData){
// get all systems
var systems = $(this).find('.' + config.systemClass);
// get new map instance or load existing
var map = getMapInstance(userData.config.id);
// trigger reset event for all Tabs
var tabContentElements = getTabContentElements();
$(tabContentElements).trigger('pf:highlightTab', [{}]);
// container must exist! otherwise systems cant be updated
if(map.getContainer() !== undefined){
$.each(systems, function(i, system){
// get user Data for System
var systemId = parseInt( $(system).data('id') );
var tempUserData = null;
$.each(userData.data.systems, function(j, systemData){
// check if any user is in this system
if(systemId === systemData.id){
tempUserData = systemData;
}
});
// check if user is currently in this system
var tempCurrentUserData = null;
if(
currentUserData &&
currentUserData.system.id === systemId
){
tempCurrentUserData = currentUserData;
}
updateSystem(map, system, tempUserData, tempCurrentUserData);
});
}
};
/**
* collect all data for export/save for a map
* @returns {{}}
*/
$.fn.getMapData = function(){
var mapElement = $(this);
var mapData = {};
// check if there is an active map counter that prevents collecting map data
var overlay = mapElement.getMapOverlay();
var counterChart = overlay.getMapCounter();
var interval = counterChart.data('interval');
if(! interval){
// map config ---------------------------------
var mapConfig = {};
mapConfig.id = mapElement.data('id');
mapConfig.name = mapElement.data('name');
mapData.config = mapConfig;
// map data -----------------------------------
var data = {};
// systems ------------------------------------
var systemsData = [];
var systems = mapElement.find('.' + config.systemClass);
for(var i = 0; i < systems.length; i++){
var tempSystem = $(systems[i]);
var systemData = {};
systemData.id = tempSystem.data('id');
systemData.alias = tempSystem.find('.' + config.systemHeadNameClass).editable('getValue', true);
systemData.status = tempSystem.data('status');
systemData.locked = tempSystem.data('locked');
systemData.rally = tempSystem.data('rally');
// position -------------------------------
var positionData = {};
var currentX = tempSystem.css('left');
var currentY = tempSystem.css('top');
// remove 'px'
positionData.x = parseInt( currentX.substring(0, currentX.length - 2) );
positionData.y = parseInt( currentY.substring(0, currentY.length - 2) );
systemData.position = positionData;
systemsData.push(systemData);
}
data.systems = systemsData;
// connections --------------------------------
var connections = [];
data.connections = connections;
mapData.data = data;
}else{
return false;
}
return mapData;
};
/**
* load system map into element
* @param mapConfig
*/
$.fn.loadMap = function(mapConfig){
// parent element where the map will be loaded
var parentElement = $(this);
// add context menus to dom
initMapContextMenu();
initConnectionContextMenu();
initSystemContextMenu();
// init jsPlumb
jsPlumb.ready(function() {
// get new map instance or load existing
mapConfig.map = getMapInstance(mapConfig.config.id);
// check for map Container (
if(mapConfig.map.getContainer() === undefined){
// new map instance
// draw initial map and set container
drawMap(parentElement, mapConfig);
// mapConfig.map.doWhileSuspended(function() {
// register all available connection types =============================
mapConfig.map.registerConnectionTypes(globalMapConfig.connectionTypes);
// set up default connections
$.each(mapConfig.data.connections, function(i, connectionData){
drawConnection(mapConfig.map, connectionData);
});
mapConfig.map.fire("pf-map-loaded", mapConfig.map);
// });
// global map observer for manual connections (drag & drop)
mapConfig.map.bind('connection', function(info, e) {
setConnectionObserver(mapConfig.map, info.connection);
});
// mapConfig.map.bind("beforeDrop", function(info) {
// manually connect
// });
// init custom scrollbars
parentElement.initMapScrollbar();
Util.showNotify({title: 'Map initialized', text: mapConfig.config.name + ' - loaded', type: 'success'});
}
});
};
/**
* init scrollbar for Map element
*/
$.fn.initMapScrollbar = function(){
// get Map Scrollbar
var scrollableElement = $(this).find('.' + config.mapWrapperClass);
initCutomScrollbar( scrollableElement );
// add map overlay container after scrollbar is initiated
// because of its absolute positon
var mapOverlay = $('', {
class: config.mapOverlayClass
});
scrollableElement.append(mapOverlay);
// reset map update timer
mapOverlay.setMapUpdateCounter(100, '5');
};
/**
* init a custom scrollbar
* @param scrollableElement
*/
var initCutomScrollbar = function( scrollableElement ){
// prevent multiple initialization
$(scrollableElement).mCustomScrollbar('destroy');
// init custom scrollbars
$(scrollableElement).mCustomScrollbar({
axis: 'x',
theme: 'light-thick',
scrollInertia: 300,
autoExpandScrollbar: false,
scrollButtons:{
scrollAmount: 30,
enable: true
},
callbacks:{
onTotalScrollOffset: 0,
onTotalScrollBackOffset: 0,
alwaysTriggerOffsets:true,
whileScrolling:function(){
// update scroll position for drag-frame-selection
var mapElement = $(scrollableElement).find('.' + config.mapClass);
$(mapElement).data('scrollLeft', this.mcs.left);
$(mapElement).data('scrollTop', this.mcs.top);
}
},
advanced: {
updateOnBrowserResize: true,
updateOnContentResize: true,
autoExpandHorizontalScroll: true
},
mouseWheel:{
enable:true,
scrollAmount: 'auto',
axis: 'x',
preventDefault: true
},
scrollbarPosition: 'inside',
autoDraggerLength: true
//autoHideScrollbar: false
});
};
/**
* scroll to a specific position in the map
* @returns {*} // string or id
*/
$.fn.scrollTo = function(position){
return this.each(function(){
// todo re-comment not used jet
//$(this).mCustomScrollbar('scrollTo', position);
});
};
/**
* removes all draggable capability for a system
*/
$.fn.destroySystemDraggable = function(){
var system = $(this);
if( system.data('ui-draggable') ){
system.draggable( 'destroy' );
}
};
/**
* drag function for single or multiple system dragging
* @param options
* @returns {*}
*/
$.fn.multiDraggable = function (options) {
// offset for each system in relation to dragSystem
var initLeftOffset = [];
var initTopOffset = [];
// max drag distance for each direction. All systems should stay within map
var maxDragDistance = {
up: 0,
right: 0,
down: 0,
left: 0
};
var mapOffset = {};
/**
* function is called during dragging. Check for valid position for each dragable system
* @param event
* @param ui
*/
var whileDragging = function(event, ui){
var dragSystem = $(event.target);
var dragSystemPosition = dragSystem.position();
var uiPosition = ui.position;
var offset = ui.offset;
var items = $(options.group);
// start map update timer
dragSystem.getMapOverlay().startMapUpdateCounter();
// get position movement from original position --------------------------------------------
var leftMove = ui.originalPosition.left - uiPosition.left;
var topMove = ui.originalPosition.top - uiPosition.top;
var dragDistance = {
up: 0,
right: 0,
down: 0,
left: 0
};
if(leftMove < 0){
dragDistance.right = leftMove * -1;
}else{
dragDistance.left = leftMove;
}
if(topMove < 0){
dragDistance.down = topMove * -1;
}else{
dragDistance.up = topMove;
}
// grid snapping ----------------------------------------------------------------------------
var leftPositionRemainder = 0;
var topPositionRemainder = 0;
// if active make system snapping to a fixed grid
if(config.mapSnapToGrid){
var snapTolerance = $(this).draggable('option', 'snapTolerance');
leftPositionRemainder = uiPosition.left % snapTolerance;
topPositionRemainder = uiPosition.top % snapTolerance;
// manipulate dragDistance
if (leftPositionRemainder <= snapTolerance) {
// ui.position.left = ui.position.left - leftRemainder;
dragDistance.left += leftPositionRemainder;
}
if (topPositionRemainder <= snapTolerance) {
// ui.position.top = ui.position.top - topRemainder;
dragDistance.up += topPositionRemainder;
}
}
// check that all systems are still inside the map -----------------------------------------
if(
dragDistance.left > maxDragDistance.left ||
dragDistance.right > maxDragDistance.right
){
// stop move current system
ui.position.left = dragSystemPosition.left;
// stop move other systems
offset.left = dragSystemPosition.left + mapOffset.left;
}else{
offset.left -= leftPositionRemainder;
ui.position.left -= leftPositionRemainder;
}
if(
dragDistance.up > maxDragDistance.up ||
dragDistance.down > maxDragDistance.down
){
// stop move current system
ui.position.top = dragSystemPosition.top;
// stop move other systems
offset.top = dragSystemPosition.top + mapOffset.top;
}else{
offset.top -= topPositionRemainder;
ui.position.top -= topPositionRemainder;
}
$.each(items || {}, function (key, tempSystem) {
tempSystem = $(tempSystem);
var left = offset.left + initLeftOffset[key];
var top = offset.top + initTopOffset[key];
var leftOffsetRemainder = 0;
var topOffsetRemainder = 0;
if(config.mapSnapToGrid){
leftOffsetRemainder = (initLeftOffset[key] % snapTolerance);
topOffsetRemainder = initTopOffset[key] % snapTolerance;
}
tempSystem.offset({
left: left - leftOffsetRemainder,
top: top - topOffsetRemainder
});
});
options.map.repaint(items);
};
return this.each(function () {
// remove previous dragging capability
$(this).destroySystemDraggable();
$(this).draggable(options, {
start: function (e, ui) {
// drag start
var dragSystem = $(e.target);
var position = dragSystem.position();
var items = $(options.group);
// start map update timer
$(e.target).getMapOverlay().startMapUpdateCounter();
// get map size
var mapElement = dragSystem.parent();
mapOffset = mapElement.offset();
var mapWidth = mapElement.width();
var mapHeight = mapElement.height();
// calculate offset for each system to dragSystem
$.each(items || {}, function (key, tempSystem) {
tempSystem = $(tempSystem);
// hide tooltip
toggleSystemTooltip( tempSystem, 'hide' );
var elemPos = tempSystem.position();
initLeftOffset[key] = elemPos.left - position.left;
initTopOffset[key] = elemPos.top - position.top;
var distanceRight = mapWidth - elemPos.left - tempSystem.outerWidth();
var distanceBottom = mapHeight - elemPos.top - tempSystem.outerHeight();
// calculate max drag distance
if(key === 0){
maxDragDistance.left = elemPos.left;
maxDragDistance.up = elemPos.top;
maxDragDistance.right = distanceRight;
maxDragDistance.down = distanceBottom;
}
if(elemPos.left < maxDragDistance.left){
maxDragDistance.left = elemPos.left;
}
if(elemPos.top < maxDragDistance.up){
maxDragDistance.up = elemPos.top;
}
if(distanceRight < maxDragDistance.right){
maxDragDistance.right = distanceRight;
}
if(distanceBottom < maxDragDistance.down){
maxDragDistance.down = distanceBottom;
}
});
},
drag: whileDragging,
stop: function(e, ui){
// stop dragging
whileDragging(e, ui);
var dragSystem = $(e.target);
var items = $(options.group);
var distanceTop = ui.position.top;
var distanceLeft = ui.position.left;
// start map update timer
dragSystem.getMapOverlay().startMapUpdateCounter();
$.each(items || {}, function (key, tempSystem) {
tempSystem = $(tempSystem);
// update z-index for dragged system + connections
updateZIndex(tempSystem);
// render tooltip
toggleSystemTooltip([tempSystem], 'show');
// set new position for popover edit field (system name)
var placement = 'top';
if(distanceTop < 100){
placement = 'bottom';
}
if(distanceLeft < 100){
placement = 'right';
}
tempSystem.find('.' + config.systemHeadNameClass).editable('option', 'placement', placement);
});
}
});
});
};
});