- New map "zoom" and map "move" options, closed #791, closed #101

- New "debug/develop" map overlays, closed #785
- Upgraded [_jsPlumb_](http://jsplumb.github.io/jsplumb/home.html) js lib `v1.7.6` → `v2.9.3`
This commit is contained in:
Mark Friedrich
2019-06-01 17:42:40 +02:00
parent 095db7a3a8
commit f4d7e3c76f
37 changed files with 13666 additions and 32325 deletions

View File

@@ -88,6 +88,12 @@ class ConnectionModel extends AbstractMapTrackingModel {
]
];
/**
* allowed connection types
* @var array
*/
protected static $connectionTypeWhitelist = ['wh_fresh', 'wh_reduced', 'wh_critical', 'frigate', 'preserve_mass'];
/**
* get connection data
* @param bool $addSignatureData
@@ -130,13 +136,15 @@ class ConnectionModel extends AbstractMapTrackingModel {
* @return int|number
*/
public function set_type($type){
$newTypes = (array)$type;
// remove unwanted types -> they should not be send from client
// -> reset keys! otherwise JSON format results in object and not in array
$type = array_values(array_intersect((array)$type, self::$connectionTypeWhitelist));
// set EOL timestamp
if( !in_array('wh_eol', $newTypes) ){
if( !in_array('wh_eol', $type) ){
$this->eolUpdated = null;
}elseif(
in_array('wh_eol', $newTypes) &&
in_array('wh_eol', $type) &&
!in_array('wh_eol', (array)$this->type) // $this->type == null for new connection! (e.g. map import)
){
// connection EOL status change

View File

@@ -33,7 +33,7 @@ requirejs.config({
velocity: 'lib/velocity.min', // v1.5.1 animation engine - http://julian.com/research/velocity
velocityUI: 'lib/velocity.ui.min', // v5.2.0 plugin for velocity - http://julian.com/research/velocity/#uiPack
slidebars: 'lib/slidebars', // v2.0.2 Slidebars - side menu plugin https://www.adchsm.com/slidebars/
jsPlumb: 'lib/dom.jsPlumb-1.7.6', // v1.7.6 jsPlumb (Vanilla)- main map draw plugin https://jsplumbtoolkit.com
jsPlumb: 'lib/jsplumb', // v2.9.3 jsPlumb main map draw plugin http://jsplumb.github.io/jsplumb/home.html
farahey: 'lib/farahey-0.5', // v0.5 jsPlumb "magnetizing" extension - https://github.com/jsplumb/farahey
customScrollbar: 'lib/jquery.mCustomScrollbar.min', // v3.1.5 Custom scroll bars - http://manos.malihu.gr
mousewheel: 'lib/jquery.mousewheel.min', // v3.1.13 Mousewheel - https://github.com/jquery/jquery-mousewheel

View File

@@ -343,51 +343,53 @@ define(['jquery'], ($) => {
}
},
wh_eol: {
cssClass: 'pf-map-connection-wh-eol',
paintStyle: {
dashstyle: '0' // solid line
}
cssClass: 'pf-map-connection-wh-eol'
},
wh_fresh: {
cssClass: 'pf-map-connection-wh-fresh',
paintStyle: {
dashstyle: '0' // solid line
}
cssClass: 'pf-map-connection-wh-fresh'
},
wh_reduced: {
cssClass: 'pf-map-connection-wh-reduced',
paintStyle: {
dashstyle: '0' // solid line
}
cssClass: 'pf-map-connection-wh-reduced'
},
wh_critical: {
cssClass: 'pf-map-connection-wh-critical',
paintStyle: {
dashstyle: '0' // solid line
}
cssClass: 'pf-map-connection-wh-critical'
},
frigate: {
cssClass: 'pf-map-connection-frig',
paintStyle: {
dashstyle: '0.99'
dashstyle: '0.5 1'
},
overlays:[
overlays: [
['Label',
{
label: 'frig',
cssClass: ['pf-map-component-overlay', 'frig'].join(' '),
location: 0.6
location: 0.7
}]
]
},
preserve_mass: {
cssClass: 'pf-map-connection-preserve-mass',
overlays:[
overlays: [
['Label',
{
label: '<i class="fas fa-fw fa-exclamation-triangle"></i>&nbsp;save mass',
cssClass: ['pf-map-component-overlay', 'mass'].join(' '),
location: 0.6
location: 0.3
}]
]
},
info_signature: {
overlays: [
['Arrow',
{
id: 'pf-map-connection-arrow-overlay',
cssClass: 'pf-map-connection-arrow-overlay',
width: 12,
length: 15,
foldback: 0.8,
direction: 1,
location: 0.5
}]
]
},
@@ -396,12 +398,12 @@ define(['jquery'], ($) => {
},
state_process: {
cssClass: 'pf-map-connection-process',
overlays:[
overlays: [
['Label',
{
label: '<i class="fas fa-fw fa-sync fa-spin"></i>',
cssClass: ['pf-map-connection-state-overlay'].join(' '),
location: 0.6
location: 0.5
}]
]
}

View File

@@ -10,6 +10,12 @@ define([
label: 'Close open dialog',
keyNames: ['ESC']
},
// map ----------------------------------------------------------------------------------------------
mapMove: {
group: 'map',
label: 'Move map section',
keyNames: ['drag', 'move']
},
// signature ----------------------------------------------------------------------------------------
signatureSelect: {
group: 'signatures',
@@ -79,12 +85,6 @@ define([
*/
let debug = false;
/**
* check interval for "new" active keys
* @type {number}
*/
let keyWatchPeriod = 100;
/**
* DOM data key for an element that lists all active events (comma separated)
* @type {string}
@@ -133,6 +133,13 @@ define([
return Object.keys(map);
};
/**
* checks whether a key is currently active (keydown)
* @param key
* @returns {boolean}
*/
let isActive = key => map.hasOwnProperty(key) && map[key] === true;
/**
* callback function that compares two arrays
* @param element
@@ -460,6 +467,7 @@ define([
};
return {
isActive: isActive,
getGroupedShortcuts: getGroupedShortcuts
};
});

View File

@@ -6,17 +6,19 @@ define([
'jquery',
'app/init',
'app/util',
'app/key',
'bootbox',
'app/map/util',
'app/map/contextmenu',
'app/map/overlay',
'app/map/overlay/overlay',
'app/map/overlay/util',
'app/map/system',
'app/map/layout',
'app/map/magnetizing',
'app/map/scrollbar',
'dragToSelect',
'app/map/local'
], ($, Init, Util, bootbox, MapUtil, MapContextMenu, MapOverlay, System, Layout, MagnetizerWrapper) => {
], ($, Init, Util, Key, bootbox, MapUtil, MapContextMenu, MapOverlay, MapOverlayUtil, System, Layout, MagnetizerWrapper, Scrollbar) => {
'use strict';
@@ -91,8 +93,7 @@ define([
},
connectionsDetachable: true, // dragOptions are set -> allow detaching them
maxConnections: 10, // due to isTarget is true, this is the max count of !out!-going connections
// isSource:true,
anchor: 'Continuous'
// isSource:true
},
target: {
filter: filterSystemHeadEvent,
@@ -104,9 +105,7 @@ define([
hoverClass: config.systemActiveClass,
activeClass: 'dragActive'
},
// isTarget:true,
// uniqueEndpoint: false,
anchor: 'Continuous'
// uniqueEndpoint: false
},
endpointTypes: Init.endpointTypes,
connectionTypes: Init.connectionTypes
@@ -130,7 +129,7 @@ define([
// -> we need BOTH endpoints of a connection -> index 0
for(let endpoint of connectionInfo[0].endpoints){
// check if there is a Label overlay
let overlay = endpoint.getOverlay(MapOverlay.endpointOverlayId);
let overlay = endpoint.getOverlay(MapOverlayUtil.config.endpointOverlayId);
if(overlay instanceof jsPlumb.Overlays.Label){
let label = overlay.getParameter('label');
overlay.setLocation(MapUtil.getEndpointOverlaySignatureLocation(endpoint, label));
@@ -588,7 +587,7 @@ define([
case 'change_status_empty':
case 'change_status_unscanned':
// change system status
system.getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(system, 'timer').startMapUpdateCounter();
let statusString = action.split('_');
@@ -730,16 +729,15 @@ define([
case 'frigate': // set as frigate hole
case 'preserve_mass': // set "preserve mass
case 'wh_eol': // set "end of life"
mapElement.getMapOverlay('timer').startMapUpdateCounter();
connection.toggleType(action);
MapOverlayUtil.getMapOverlay(mapElement, 'timer').startMapUpdateCounter();
MapUtil.toggleConnectionType(connection, action);
MapUtil.markAsChanged(connection);
break;
case 'status_fresh':
case 'status_reduced':
case 'status_critical':
let newStatus = action.split('_')[1];
mapElement.getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(mapElement, 'timer').startMapUpdateCounter();
MapUtil.setConnectionWHStatus(connection, 'wh_' + newStatus);
MapUtil.markAsChanged(connection);
break;
@@ -751,7 +749,7 @@ define([
bootbox.confirm('Change scope from ' + scopeName + ' to ' + newScopeName + '?', function(result){
if(result){
mapElement.getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(mapElement, 'timer').startMapUpdateCounter();
setConnectionScope(connection, newScope);
@@ -775,7 +773,7 @@ define([
switch(action){
case 'bubble':
mapElement.getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(mapElement, 'timer').startMapUpdateCounter();
endpoint.toggleType(action);
for(let connection of endpoint.connections){
@@ -860,7 +858,7 @@ define([
source: sourceSystem[0],
target: targetSystem[0],
scope: connectionData.scope || map.Defaults.Scope,
type: (connectionData.type || MapUtil.getDefaultConnectionTypeByScope(map.Defaults.Scope)).join(' ')
//type: (connectionData.type || MapUtil.getDefaultConnectionTypeByScope(map.Defaults.Scope)).join(' ')
/* experimental set "static" connection parameters in initial load
parameters: {
connectionId: connectionId,
@@ -878,6 +876,7 @@ define([
// check if connection is valid (e.g. source/target exist
if(connection instanceof jsPlumb.Connection){
connection.addType((connectionData.type || MapUtil.getDefaultConnectionTypeByScope(map.Defaults.Scope)).join(' '));
// set connection parameters
// they should persist even through connection type change (e.g. wh -> stargate,..)
@@ -1145,7 +1144,7 @@ define([
mapWrapper.setMapShortcuts();
// show static overlay actions
let mapOverlay = mapContainer.getMapOverlay('info');
let mapOverlay = MapOverlayUtil.getMapOverlay(mapContainer, 'info');
mapOverlay.updateOverlayIcon('systemRegion', 'show');
mapOverlay.updateOverlayIcon('connection', 'show');
mapOverlay.updateOverlayIcon('connectionEol', 'show');
@@ -1316,7 +1315,7 @@ define([
deleteConnection.source &&
deleteConnection.target
){
mapConfig.map.detach(deleteConnection, {fireEvent: false});
mapConfig.map.deleteConnection(deleteConnection, {fireEvent: false});
}
}
}
@@ -1626,12 +1625,12 @@ define([
Util.showNotify({title: title, text: 'Scope: ' + scope, type: 'success'});
}else{
// some save errors
payload.context.map.detach(payload.context.connection, {fireEvent: false});
payload.context.map.deleteConnection(payload.context.connection, {fireEvent: false});
}
},
payload => {
// remove this connection from map
payload.context.map.detach(payload.context.connection, {fireEvent: false});
payload.context.map.deleteConnection(payload.context.connection, {fireEvent: false});
Util.handleAjaxErrorResponse(payload);
}
);
@@ -1830,7 +1829,7 @@ define([
start: function(params){
let dragSystem = $(params.el);
mapOverlayTimer = dragSystem.getMapOverlay('timer');
mapOverlayTimer = MapOverlayUtil.getMapOverlay(dragSystem, 'timer');
// start map update timer
mapOverlayTimer.startMapUpdateCounter();
@@ -2047,7 +2046,7 @@ define([
revalidate(map, system);
if(!hideCounter){
$(system).getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(system, 'timer').startMapUpdateCounter();
}
};
@@ -2063,18 +2062,33 @@ define([
jsPlumb.Defaults.LogEnabled = true;
let newJsPlumbInstance = jsPlumb.getInstance({
Anchor: 'Continuous', // anchors on each site
Container: null, // will be set as soon as container is connected to DOM
Anchor: ['Continuous', {faces: ['top', 'right', 'bottom', 'left']}], // single anchor (used during drag action)
Anchors: [
['Continuous', {faces: ['top', 'right', 'bottom', 'left']}],
['Continuous', {faces: ['top', 'right', 'bottom', 'left']}],
],
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.
strokeWidth: 4, // connection width (inner)
stroke: '#3c3f41', // connection color (inner)
outlineWidth: 2, // connection width (outer)
outlineStroke: '#63676a', // connection color (outer)
dashstyle: '0', // connection dashstyle (default) -> is used after connectionType got removed that has dashstyle specified
'stroke-linecap': 'round' // connection shape
},
Connector: [ 'Bezier', { curviness: 40 } ], // default connector style (this is not used!) all connections have their own style (by scope)
Endpoint: [ 'Dot', { radius: 5 } ],
ReattachConnections: false, // re-attach connection if dragged with mouse to "nowhere"
Scope: Init.defaultMapScope, // default map scope for connections
Endpoint: ['Dot', {radius: 5}], // single endpoint (used during drag action)
Endpoints: [
['Dot', {radius: 5, cssClass: config.endpointSourceClass}],
['Dot', {radius: 5, cssClass: config.endpointTargetClass}]
],
EndpointStyle: {fill: '#3c3f41', stroke: '#63676a', strokeWidth: 2}, // single endpoint style (used during drag action)
EndpointStyles: [
{fill: '#3c3f41', stroke: '#63676a', strokeWidth: 2},
{fill: '#3c3f41', stroke: '#63676a', strokeWidth: 2}
],
Connector: ['Bezier', {curviness: 40}], // default connector style (this is not used!) all connections have their own style (by scope)
ReattachConnections: false, // re-attach connection if dragged with mouse to "nowhere"
Scope: Init.defaultMapScope, // default map scope for connections
LogEnabled: true
});
@@ -2181,6 +2195,13 @@ define([
});
// Notification an existing Connection is being dragged.
// Note that when this event fires for a brand new Connection, the target of the Connection is a transient element
// that jsPlumb is using for dragging, and will be removed from the DOM when the Connection is subsequently either established or aborted.
newJsPlumbInstance.bind('connectionDrag', function(info, e){
});
// Notification a Connection was detached.
// In the event that the Connection was new and had never been established between two Endpoints, it has a pending flag set on it.
newJsPlumbInstance.bind('connectionDetached', function(info, e){
@@ -2200,6 +2221,11 @@ define([
});
// Notification the current zoom was changed
newJsPlumbInstance.bind('zoom', function(zoom){
MapOverlay.updateZoomOverlay(this);
});
// ========================================================================================================
// Events for interactive CSS classes https://community.jsplumbtoolkit.com/doc/styling-via-css.html
//=========================================================================================================
@@ -2276,6 +2302,8 @@ define([
// get map container
let mapContainer = $(map.getContainer());
MapOverlay.initMapDebugOverlays(map);
// context menu for mapContainer
mapContainer.on('contextmenu', function(e){
e.preventDefault();
@@ -2472,14 +2500,14 @@ define([
// toggle "fullSize" Endpoint overlays for system (signature information) -------------------------------------
mapContainer.hoverIntent({
over: function(e){
for(let overlayInfo of map.selectEndpoints({element: this}).getOverlay(MapOverlay.endpointOverlayId)){
for(let overlayInfo of map.selectEndpoints({element: this}).getOverlay(MapOverlayUtil.config.endpointOverlayId)){
if(overlayInfo[0] instanceof jsPlumb.Overlays.Label){
overlayInfo[0].fire('toggleSize', true);
}
}
},
out: function(e){
for(let overlayInfo of map.selectEndpoints({element: this}).getOverlay(MapOverlay.endpointOverlayId)){
for(let overlayInfo of map.selectEndpoints({element: this}).getOverlay(MapOverlayUtil.config.endpointOverlayId)){
if(overlayInfo[0] instanceof jsPlumb.Overlays.Label){
overlayInfo[0].fire('toggleSize', false);
}
@@ -2526,7 +2554,7 @@ define([
}
// show map overlay info icon
this.mapElement.getMapOverlay('info').updateOverlayIcon(this.mapOption.option, 'hide');
MapOverlayUtil.getMapOverlay(this.mapElement, 'info').updateOverlayIcon(this.mapOption.option, 'hide');
// delete map option
MapUtil.deleteLocalData('map', this.mapElement.data('id'), this.mapOption.option );
@@ -2545,7 +2573,7 @@ define([
}
// hide map overlay info icon
this.mapElement.getMapOverlay('info').updateOverlayIcon(this.mapOption.option, 'show');
MapOverlayUtil.getMapOverlay(this.mapElement, 'info').updateOverlayIcon(this.mapOption.option, 'show');
// store map option
MapUtil.storeLocalData('map', this.mapElement.data('id'), this.mapOption.option, 1 );
@@ -2591,7 +2619,7 @@ define([
if(select){
let mapWrapper = mapElement.closest('.' + config.mapWrapperClass);
mapWrapper.scrollToSystem(MapUtil.getSystemPosition(system));
Scrollbar.scrollToSystem(mapWrapper, MapUtil.getSystemPosition(system));
// select system
MapUtil.showSystemInfo(map, system);
}
@@ -2622,7 +2650,7 @@ define([
// update "local" overlay for this map
mapContainer.on('pf:updateLocal', function(e, userData){
let mapElement = $(this);
let mapOverlay = mapElement.getMapOverlay('local');
let mapOverlay = MapOverlayUtil.getMapOverlay(mapElement, 'local');
if(userData && userData.config && userData.config.id){
let currentMapData = Util.getCurrentMapData(userData.config.id);
@@ -2826,7 +2854,7 @@ define([
let getMapDataForSync = (mapContainer, filter = [], minimal = false) => {
let mapData = false;
// check if there is an active map counter that prevents collecting map data (locked map)
if(!mapContainer.getMapOverlayInterval()){
if(!MapOverlayUtil.getMapOverlayInterval(mapContainer)){
mapData = mapContainer.getMapDataFromClient(filter, minimal);
}
return mapData;
@@ -3044,6 +3072,96 @@ define([
mapWrapperElement.initCustomScrollbar({
callbacks: {
onInit: function(){
// init 'space' key + 'mouse' down for map scroll -------------------------------------------------
let scrollStart = [0, 0];
let mouseStart = [0, 0];
let mouseOffset = [0, 0];
let animationFrameId = 0;
let toggleDragScroll = active => {
mapElement.toggleClass('disabled', active).toggleClass(' pf-map-move', active);
};
let stopDragScroll = () => {
cancelAnimationFrame(animationFrameId);
animationFrameId = 0;
scrollStart = [0, 0];
mouseStart = [0, 0];
mouseOffset = [0, 0];
};
let dragScroll = () => {
if(Key.isActive(' ')){
let scrollOffset = [
Math.max(0, scrollStart[0] - mouseOffset[0]),
Math.max(0, scrollStart[1] - mouseOffset[1])
];
if(
scrollOffset[0] !== Math.abs(this.mcs.left) ||
scrollOffset[1] !== Math.abs(this.mcs.top)
){
Scrollbar.scrollToPosition(this, [scrollOffset[1], scrollOffset[0]], {
scrollInertia: 0,
scrollEasing: 'linear',
timeout: 5
});
}
// recursive re-call on next render
animationFrameId = requestAnimationFrame(dragScroll);
}
};
let keyDownHandler = function(e){
if(e.keyCode === 32){
e.preventDefault();
toggleDragScroll(true);
}
};
let keyUpHandler = function(e){
if(e.keyCode === 32){
e.preventDefault();
toggleDragScroll(false);
}
};
let mouseMoveHandler = function(e){
if(animationFrameId){
mouseOffset[0] = e.clientX - mouseStart[0];
mouseOffset[1] = e.clientY - mouseStart[1];
}
// space activated on mouse move
toggleDragScroll(Key.isActive(' '));
};
let mouseDownHandler = function(e){
if(!animationFrameId && e.which === 1 && Key.isActive(' ')){
scrollStart[0] = Math.abs(this.mcs.left);
scrollStart[1] = Math.abs(this.mcs.top);
mouseStart[0] = e.clientX;
mouseStart[1] = e.clientY;
toggleDragScroll(true);
animationFrameId = requestAnimationFrame(dragScroll);
}
};
let mouseUpHandler = function(e){
if(e.which === 1){
stopDragScroll();
}
};
this.addEventListener('keydown', keyDownHandler, { capture: false });
this.addEventListener('keyup', keyUpHandler, { capture: false });
this.addEventListener('mousemove', mouseMoveHandler, { capture: false });
this.addEventListener('mousedown', mouseDownHandler, { capture: false });
this.addEventListener('mouseup', mouseUpHandler, { capture: false });
},
onScroll: function(){
// scroll complete
// update scroll position for drag-frame-selection
@@ -3070,7 +3188,6 @@ define([
// add map overlays after scrollbar is initialized
// because of its absolute position
mapWrapperElement.initMapOverlays();
mapWrapperElement.initLocalOverlay(mapId);
};

View File

@@ -6,36 +6,11 @@ define([
'jquery',
'app/init',
'app/util',
'app/map/overlay/util',
'app/map/util'
], ($, Init, Util, MapUtil) => {
], ($, Init, Util, MapOverlayUtil, MapUtil) => {
'use strict';
let config = {
logTimerCount: 3, // map log timer in seconds
// map overlay positions
mapOverlayClass: 'pf-map-overlay', // class for all map overlays
mapOverlayTimerClass: 'pf-map-overlay-timer', // class for map overlay timer e.g. map timer
mapOverlayInfoClass: 'pf-map-overlay-info', // class for map overlay info e.g. map info
overlayLocalClass: 'pf-map-overlay-local', // class for map overlay "local" table
// system
systemHeadClass: 'pf-system-head', // class for system head
// overlay IDs
connectionOverlayWhId: 'pf-map-connection-wh-overlay', // connection WH overlay ID (jsPlumb)
connectionOverlayEolId: 'pf-map-connection-eol-overlay', // connection EOL overlay ID (jsPlumb)
connectionOverlayArrowId: 'pf-map-connection-arrow-overlay', // connection Arrows overlay ID (jsPlumb)
endpointOverlayId: 'pf-map-endpoint-overlay', // endpoint overlay ID (jsPlumb)
// overlay classes
componentOverlayClass: 'pf-map-component-overlay', // class for "normal size" overlay
connectionArrowOverlayClass: 'pf-map-connection-arrow-overlay', // class for "connection arrow" overlay
connectionDiamondOverlayClass: 'pf-map-connection-diamond-overlay' // class for "connection diamond" overlay
};
/**
* get MapObject (jsPlumb) from mapElement
* @param mapElement
@@ -43,7 +18,7 @@ define([
*/
let getMapObjectFromMapElement = mapElement => {
let Map = require('app/map/map');
return Map.getMapInstance( mapElement.data('id') );
return Map.getMapInstance(mapElement.data('id'));
};
/**
@@ -53,8 +28,7 @@ define([
*/
let getMapObjectFromOverlayIcon = overlayIcon => {
let mapElement = Util.getMapElementFromOverlay(overlayIcon);
return getMapObjectFromMapElement( mapElement );
return getMapObjectFromMapElement(mapElement);
};
/**
@@ -65,127 +39,164 @@ define([
let addEndpointOverlaySignatureLabel = (endpoint, labelData) => {
let label = labelData.labels.join(', ');
let name = labelData.names.join(', ');
let overlay = endpoint.getOverlay(MapOverlayUtil.config.endpointOverlayId);
endpoint.addOverlay([
'Label',
{
label: MapUtil.formatEndpointOverlaySignatureLabel(label),
id: config.endpointOverlayId,
cssClass: [config.componentOverlayClass, label.length ? 'small' : 'icon'].join(' '),
location: MapUtil.getEndpointOverlaySignatureLocation(endpoint, label),
events: {
toggleSize: function(fullSize){
let signatureName = this.getParameter('signatureName');
if(fullSize && !this.getParameter('fullSize') && signatureName){
this.setLabel(this.getLabel() + '<br>' + '<span class="initialism">' + signatureName + '</span>');
this.setParameter('fullSize', true);
}else if(this.getParameter('fullSize')){
this.setLabel(MapUtil.formatEndpointOverlaySignatureLabel(this.getParameter('label')));
this.setParameter('fullSize', false);
}
}
},
parameters: {
fullSize: false,
label: label,
signatureName: name
}
}
]);
};
/**
* add overlays to connections (signature based data)
* @param connections
* @param connectionsData
*/
let addConnectionsOverlay = (connections, connectionsData) => {
let SystemSignatures = require('app/ui/module/system_signature');
// loop through all map connections (get from DOM)
for(let connection of connections){
let connectionId = connection.getParameter('connectionId');
let sourceEndpoint = connection.endpoints[0];
let targetEndpoint = connection.endpoints[1];
let signatureTypeData = {
source: {
names: [],
labels: []
},
target: {
names: [],
labels: []
}
};
// ... find matching connectionData (from Ajax)
for(let connectionData of connectionsData){
if(connectionData.id === connectionId){
signatureTypeData = MapUtil.getConnectionDataFromSignatures(connection, connectionData);
// ... connection matched -> continue with next one
break;
}
}
// add endpoint overlays ------------------------------------------------------
addEndpointOverlaySignatureLabel(sourceEndpoint, signatureTypeData.source);
addEndpointOverlaySignatureLabel(targetEndpoint, signatureTypeData.target);
let sourceLabel = signatureTypeData.source.labels;
let targetLabel = signatureTypeData.target.labels;
// add arrow (connection) overlay that points from "XXX" => "K162" ------------
let overlayType = 'Diamond'; // not specified
let arrowDirection = 1;
if(overlay instanceof jsPlumb.Overlays.Label){
// update existing overlay
if(
(sourceLabel.indexOf('K162') !== -1 && targetLabel.indexOf('K162') !== -1) ||
(sourceLabel.length === 0 && targetLabel.length === 0) ||
(
sourceLabel.length > 0 && targetLabel.length > 0 &&
sourceLabel.indexOf('K162') === -1 && targetLabel.indexOf('K162') === -1
)
label !== overlay.getParameter('label') ||
name !== overlay.getParameter('signatureName')
){
// unknown direction
overlayType = 'Diamond'; // not specified
arrowDirection = 1;
}else if(
(sourceLabel.indexOf('K162') !== -1) ||
(sourceLabel.length === 0 && targetLabel.indexOf('K162') === -1)
){
// convert default arrow direction
overlayType = 'Arrow';
arrowDirection = -1;
}else{
// default arrow direction is fine
overlayType = 'Arrow';
arrowDirection = 1;
// update label only on label changes
overlay.setLabel(MapUtil.formatEndpointOverlaySignatureLabel(label));
overlay.setParameter('fullSize', false);
overlay.setParameter('label', label);
overlay.setParameter('signatureName', name);
overlay.updateClasses(label.length ? 'small' : 'icon', label.length ? 'icon' : 'small');
overlay.setLocation(MapUtil.getEndpointOverlaySignatureLocation(endpoint, label));
}
connection.addOverlay([
overlayType,
}else{
// add new overlay
endpoint.addOverlay([
'Label',
{
width: 12,
length: 15,
location: 0.5,
foldback: 0.85,
direction: arrowDirection,
id: config.connectionOverlayArrowId,
cssClass: (overlayType === 'Arrow') ? config.connectionArrowOverlayClass : config.connectionDiamondOverlayClass
label: MapUtil.formatEndpointOverlaySignatureLabel(label),
id: MapOverlayUtil.config.endpointOverlayId,
cssClass: [MapOverlayUtil.config.componentOverlayClass, label.length ? 'small' : 'icon'].join(' '),
location: MapUtil.getEndpointOverlaySignatureLocation(endpoint, label),
events: {
toggleSize: function(fullSize){
let signatureName = this.getParameter('signatureName');
if(fullSize && !this.getParameter('fullSize') && signatureName){
this.setLabel(this.getLabel() + '<br>' + '<span class="initialism">' + signatureName + '</span>');
this.setParameter('fullSize', true);
}else if(this.getParameter('fullSize')){
this.setLabel(MapUtil.formatEndpointOverlaySignatureLabel(this.getParameter('label')));
this.setParameter('fullSize', false);
}
}
},
parameters: {
fullSize: false,
label: label,
signatureName: name
}
}
]);
}
};
/**
* remove overviews from a Tooltip
* @param endpoint
* @param i
* add overlays to connections (signature based data)
* @param map
* @param connectionsData
*/
let removeEndpointOverlay = (endpoint, i) => {
endpoint.removeOverlays(config.endpointOverlayId);
let updateInfoSignatureOverlays = (map, connectionsData) => {
let type = 'info_signature';
let SystemSignatures = require('app/ui/module/system_signature');
connectionsData = Util.arrayToObject(connectionsData);
map.batch(function(){
map.getAllConnections().forEach(function(connection){
let connectionId = connection.getParameter('connectionId');
let sourceEndpoint = connection.endpoints[0];
let targetEndpoint = connection.endpoints[1];
let signatureTypeData = {
source: {
names: [],
labels: []
},
target: {
names: [],
labels: []
}
};
if(connection.scope === 'wh'){
if(!connection.hasType(type)){
connection.addType(type);
}
let overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
// Arrow overlay needs to be cleared() (removed) if 'info_signature' gets removed!
// jsPlumb does not handle overlay updates for Arrow overlays... so we need to re-apply the the overlay manually
if(overlayArrow.path && !overlayArrow.path.isConnected){
connection.canvas.appendChild(overlayArrow.path);
}
let overlayType = 'Diamond'; // not specified
let arrowDirection = 1;
let arrowFoldback = 2;
if(connectionsData.hasOwnProperty(connectionId)){
// signature data found for current connection
signatureTypeData = MapUtil.getConnectionDataFromSignatures(connection, connectionsData[connectionId]);
let sourceLabel = signatureTypeData.source.labels;
let targetLabel = signatureTypeData.target.labels;
// add arrow (connection) overlay that points from "XXX" => "K162" ------------------------------------
if(
(sourceLabel.indexOf('K162') !== -1 && targetLabel.indexOf('K162') !== -1) ||
(sourceLabel.length === 0 && targetLabel.length === 0) ||
(
sourceLabel.length > 0 && targetLabel.length > 0 &&
sourceLabel.indexOf('K162') === -1 && targetLabel.indexOf('K162') === -1
)
){
// unknown direction
overlayType = 'Diamond'; // not specified
arrowDirection = 1;
arrowFoldback = 2;
}else if(
(sourceLabel.indexOf('K162') !== -1) ||
(sourceLabel.length === 0 && targetLabel.indexOf('K162') === -1)
){
// convert default arrow direction
overlayType = 'Arrow';
arrowDirection = -1;
arrowFoldback = 0.8;
}else{
// default arrow direction is fine
overlayType = 'Arrow';
arrowDirection = 1;
arrowFoldback = 0.8;
}
}
// class changes must be done on "connection" itself not on "overlayArrow"
// -> because Arrow might not be rendered to map at this point (if it does not exist already)
if(overlayType === 'Arrow'){
connection.updateClasses(
MapOverlayUtil.config.connectionArrowOverlaySuccessClass,
MapOverlayUtil.config.connectionArrowOverlayDangerClass
);
}else{
connection.updateClasses(
MapOverlayUtil.config.connectionArrowOverlayDangerClass,
MapOverlayUtil.config.connectionArrowOverlaySuccessClass
);
}
overlayArrow.updateFrom({
direction: arrowDirection,
foldback: arrowFoldback
});
// add endpoint overlays --------------------------------------------------------------------------
addEndpointOverlaySignatureLabel(sourceEndpoint, signatureTypeData.source);
addEndpointOverlaySignatureLabel(targetEndpoint, signatureTypeData.target);
}else{
// connection is not 'wh' scope
if(connection.hasType(type)){
connection.removeType(type);
}
}
});
});
};
/**
@@ -237,11 +248,10 @@ define([
/**
* git signature data that is linked to a connection for a mapId
* @param mapElement
* @param connections
* @param callback
*/
let getConnectionSignatureData = (mapElement, connections, callback) => {
let mapOverlay = $(mapElement).getMapOverlay('info');
let getConnectionSignatureData = (mapElement, callback) => {
let mapOverlay = MapOverlayUtil.getMapOverlay(mapElement, 'info');
let overlayConnectionIcon = mapOverlay.find('.pf-map-overlay-endpoint');
showLoading(overlayConnectionIcon);
@@ -259,46 +269,48 @@ define([
dataType: 'json',
context: {
mapElement: mapElement,
connections: connections,
overlayConnectionIcon: overlayConnectionIcon
}
}).done(function(connectionsData){
// hide all connection before add them (refresh)
this.mapElement.hideEndpointOverlays();
// ... add overlays
callback(this.connections, connectionsData);
let map = getMapObjectFromMapElement(this.mapElement);
callback(map, connectionsData);
}).always(function(){
hideLoading(this.overlayConnectionIcon);
});
};
/**
* showEndpointOverlays
* showInfoSignatureOverlays
* -> used by "refresh" overlays (hover) AND/OR initial menu trigger
*/
$.fn.showEndpointOverlays = function(){
$.fn.showInfoSignatureOverlays = function(){
let mapElement = $(this);
let map = getMapObjectFromMapElement(mapElement);
let MapUtil = require('app/map/util');
let connections = MapUtil.searchConnectionsByScopeAndType(map, 'wh', undefined, true);
// get connection signature information ---------------------------------------
getConnectionSignatureData(mapElement, connections, addConnectionsOverlay);
getConnectionSignatureData(mapElement, updateInfoSignatureOverlays);
};
/**
* hideEndpointOverlays
* -> see showEndpointOverlays()
* hideInfoSignatureOverlays
* -> see showInfoSignatureOverlays()
*/
$.fn.hideEndpointOverlays = function(){
$.fn.hideInfoSignatureOverlays = function(){
let map = getMapObjectFromMapElement($(this));
let MapUtil = require('app/map/util');
let connections = MapUtil.searchConnectionsByScopeAndType(map, 'wh');
let type = 'info_signature';
for(let connection of connections){
connection.removeOverlays(config.connectionOverlayArrowId);
connection.endpoints.forEach(removeEndpointOverlay);
}
map.batch(function(){
map.getAllConnections().forEach(function(connection){
let overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
if(overlayArrow){
overlayArrow.cleanup();
}
if(connection.hasType(type)){
connection.removeType(type, {}, true);
}
});
map.selectEndpoints().removeOverlay(MapOverlayUtil.config.endpointOverlayId);
});
};
/**
@@ -343,7 +355,7 @@ define([
hoverIntent: {
over: function(e){
let mapElement = Util.getMapElementFromOverlay(this);
mapElement.find('.' + config.systemHeadClass).each(function(){
mapElement.find('.' + MapOverlayUtil.config.systemHeadClass).each(function(){
let systemHead = $(this);
// init popover if not already exists
if(!systemHead.data('bs.popover')){
@@ -366,7 +378,7 @@ define([
},
out: function(e){
let mapElement = Util.getMapElementFromOverlay(this);
mapElement.find('.' + config.systemHeadClass).popover('hide');
mapElement.find('.' + MapOverlayUtil.config.systemHeadClass).popover('hide');
}
}
},
@@ -378,7 +390,7 @@ define([
hoverIntent: {
over: function(e){
let mapElement = Util.getMapElementFromOverlay(this);
mapElement.showEndpointOverlays();
mapElement.showInfoSignatureOverlays();
},
out: function(e){
// just "refresh" on hover
@@ -399,11 +411,10 @@ define([
hoverIntent: {
over: function(e){
let map = getMapObjectFromOverlayIcon(this);
let MapUtil = require('app/map/util');
let connections = MapUtil.searchConnectionsByScopeAndType(map, 'wh');
let serverDate = Util.getServerTime();
// show connection overlays ---------------------------------------------------
// show connection overlays -----------------------------------------------------------------------
for(let connection of connections){
let createdTimestamp = connection.getParameter('created');
let updatedTimestamp = connection.getParameter('updated');
@@ -420,13 +431,13 @@ define([
'<i class="fas fa-fw fa-pen-square"></i>&nbsp;' + formatTimeParts(updatedDiff)
];
// add label overlay ------------------------------------------------------
// add label overlay --------------------------------------------------------------------------
connection.addOverlay([
'Label',
{
label: labels.join('<br>'),
id: config.connectionOverlayWhId,
cssClass: [config.componentOverlayClass, 'small'].join(' '),
id: MapOverlayUtil.config.connectionOverlayWhId,
cssClass: [MapOverlayUtil.config.componentOverlayClass, 'small'].join(' '),
location: 0.35
}
]);
@@ -434,11 +445,10 @@ define([
},
out: function(e){
let map = getMapObjectFromOverlayIcon(this);
let MapUtil = require('app/map/util');
let connections = MapUtil.searchConnectionsByScopeAndType(map, 'wh');
for(let connection of connections){
connection.removeOverlays(config.connectionOverlayWhId);
connection.removeOverlay(MapOverlayUtil.config.connectionOverlayWhId);
}
}
}
@@ -451,7 +461,6 @@ define([
hoverIntent: {
over: function(e){
let map = getMapObjectFromOverlayIcon(this);
let MapUtil = require('app/map/util');
let connections = MapUtil.searchConnectionsByScopeAndType(map, 'wh', ['wh_eol']);
let serverDate = Util.getServerTime();
@@ -464,8 +473,8 @@ define([
'Label',
{
label: '<i class="far fa-fw fa-clock"></i>&nbsp;' + formatTimeParts(diff),
id: config.connectionOverlayEolId,
cssClass: [config.componentOverlayClass, 'eol'].join(' '),
id: MapOverlayUtil.config.connectionOverlayEolId,
cssClass: [MapOverlayUtil.config.componentOverlayClass, 'eol'].join(' '),
location: 0.25
}
]);
@@ -473,53 +482,26 @@ define([
},
out: function(e){
let map = getMapObjectFromOverlayIcon(this);
let MapUtil = require('app/map/util');
let connections = MapUtil.searchConnectionsByScopeAndType(map, 'wh', ['wh_eol']);
for(let connection of connections){
connection.removeOverlay(config.connectionOverlayEolId);
connection.removeOverlay(MapOverlayUtil.config.connectionOverlayEolId);
}
}
}
}
};
/**
* get map overlay element by type e.g. timer/counter, info - overlay
* @param overlayType
* @returns {*}
*/
$.fn.getMapOverlay = function(overlayType){
let mapWrapperElement = $(this).parents('.' + MapUtil.config.mapWrapperClass);
let mapOverlay = null;
switch(overlayType){
case 'timer':
mapOverlay = mapWrapperElement.find('.' + config.mapOverlayTimerClass);
break;
case 'info':
mapOverlay = mapWrapperElement.find('.' + config.mapOverlayInfoClass);
break;
case 'local':
mapOverlay = mapWrapperElement.find('.' + config.overlayLocalClass);
break;
}
return mapOverlay;
};
/**
* draws the map update counter to the map overlay timer
* @param mapOverlayTimer
* @param percent
* @param value
* @returns {*}
*/
$.fn.setMapUpdateCounter = function(percent, value){
let mapOverlayTimer = $(this);
let setMapUpdateCounter = (mapOverlayTimer, percent, value) => {
// check if counter already exists
let counterChart = mapOverlayTimer.getMapCounter();
let counterChart = MapOverlayUtil.getMapCounter(mapOverlayTimer);
if(counterChart.length === 0){
// create new counter
@@ -546,27 +528,14 @@ define([
return counterChart;
};
/**
* get the map counter chart from overlay
* @returns {JQuery|*|T|{}|jQuery}
*/
$.fn.getMapCounter = function(){
return $(this).find('.' + Init.classes.pieChart.pieChartMapCounterClass);
};
$.fn.getMapOverlayInterval = function(){
return $(this).getMapOverlay('timer').getMapCounter().data('interval');
};
/**
* start the map update counter or reset
*/
$.fn.startMapUpdateCounter = function(){
let mapOverlayTimer = $(this);
let counterChart = mapOverlayTimer.getMapCounter();
let counterChart = MapOverlayUtil.getMapCounter(mapOverlayTimer);
let maxSeconds = config.logTimerCount;
let maxSeconds = MapOverlayUtil.config.logTimerCount;
let counterChartLabel = counterChart.find('span');
@@ -709,6 +678,154 @@ define([
}
};
/**
* update map zoom overlay information
* @param map
*/
let updateZoomOverlay = map => {
let zoom = map.getZoom();
let zoomPercent = Math.round(zoom * 1000) / 10;
let zoomOverlay = MapOverlayUtil.getMapOverlay(map.getContainer(), 'zoom');
let zoomValue = zoomOverlay.find('.' + MapOverlayUtil.config.zoomOverlayValueClass);
let zoomUp = zoomOverlay.find('.' + MapOverlayUtil.config.zoomOverlayUpClass);
let zoomDown = zoomOverlay.find('.' + MapOverlayUtil.config.zoomOverlayDownClass);
zoomValue.toggleClass('active', zoom !== 1).text(zoomPercent);
zoomUp.toggleClass('disabled', zoom >= MapUtil.config.zoomMax);
zoomDown.toggleClass('disabled', zoom <= MapUtil.config.zoomMin);
};
/**
* map debug overlays for connections/endpoints
* -> requires manual added "debug" GET param to URL
* @param map
*/
let initMapDebugOverlays = map => {
let url = new URL(window.location.href);
if(url.searchParams.has('debug')){
let mapContainer = $(map.getContainer());
// debug map overlays for connection/endpoints
mapContainer.on('mouseover', '.jtk-connector', function(e){
e.stopPropagation();
if(e.target.classList.contains('jtk-connector-outline')){
let connection = e.currentTarget._jsPlumb;
// show debug overlay only if there is no active debug
if(!connection.getOverlay(MapOverlayUtil.config.debugOverlayId)){
// find nearby connections
let connections = [];
let endpoints = [];
let hasComponentId = id => {
return component => component.id === id;
};
for(let endpoint of connection.endpoints){
let connectionsInfo = map.anchorManager.getConnectionsFor(endpoint.elementId);
for(let connectionInfo of connectionsInfo){
if(!connections.some(hasComponentId(connectionInfo[0].id))){
connections.push(connectionInfo[0]);
for(let endpointTemp of connectionInfo[0].endpoints){
if(!endpoints.some(hasComponentId(endpointTemp.id))){
endpoints.push(endpointTemp);
}
}
}
}
}
let createConnectionOverlay = connection => {
let data = MapUtil.getDataByConnection(connection);
let html = '<div><table>';
html += '<tr><td>' + connection.id + '</td><td class="text-right">' + data.id + '</td></tr>';
html += '<tr><td>Scope:</td><td class="text-right">' + data.scope + '</td></tr>';
html += '<tr><td>Type:</td><td class="text-right">' + data.type.toString() + '</td></tr>';
html += '</table></div>';
return $(html).on('click', function(){
console.info(connection);
});
};
for(let connection of connections){
connection.addOverlay([
'Custom',
{
id: MapOverlayUtil.config.debugOverlayId,
cssClass: [MapOverlayUtil.config.componentOverlayClass, 'debug'].join(' '),
create: createConnectionOverlay
}
]);
}
let createEndpointOverlay = endpoint => {
let types = MapUtil.filterDefaultTypes(endpoint.getType());
let html = '<div><table>';
html += '<tr><td>' + endpoint.id + '</td><td class="text-right"></td></tr>';
html += '<tr><td>Scope:</td><td class="text-right">' + endpoint.scope + '</td></tr>';
html += '<tr><td>Type:</td><td class="text-right">' + types.toString() + '</td></tr>';
html += '</table></div>';
return $(html).on('click', function(){
console.info(endpoint);
});
};
for(let endpoint of endpoints){
endpoint.addOverlay([
'Custom',
{
id: MapOverlayUtil.config.debugOverlayId,
cssClass: [MapOverlayUtil.config.componentOverlayClass, 'debug'].join(' '),
create: createEndpointOverlay
}
]);
}
}
}
});
mapContainer.on('mouseover', function(e){
e.stopPropagation();
if(e.target === e.currentTarget){
map.select().removeOverlay(MapOverlayUtil.config.debugOverlayId);
map.selectEndpoints().removeOverlay(MapOverlayUtil.config.debugOverlayId);
}
});
}
};
/**
* init map zoom overlay
* @returns {jQuery}
*/
let initZoomOverlay = () => {
let clickHandler = e => {
let zoomIcon = $(e.target);
if(!zoomIcon.hasClass('disabled')){
let zoomAction = zoomIcon.attr('data-zoom');
let map = getMapObjectFromOverlayIcon(zoomIcon);
MapUtil.changeZoom(map, zoomAction);
}
};
return $('<div>', {
class: [MapOverlayUtil.config.mapOverlayClass, MapOverlayUtil.config.mapOverlayZoomClass].join(' ')
}).append(
$('<i>', {
class: ['fas', 'fa-caret-up', MapOverlayUtil.config.zoomOverlayUpClass].join(' ')
}).attr('data-zoom', 'up').on('click', clickHandler),
$('<span>', {
class: MapOverlayUtil.config.zoomOverlayValueClass,
text: '100'
}),
$('<i>', {
class: ['fas', 'fa-caret-down', MapOverlayUtil.config.zoomOverlayDownClass].join(' ')
}).attr('data-zoom', 'down').on('click', clickHandler)
);
};
/**
* init all map overlays on a "parent" element
* @returns {*}
@@ -718,14 +835,17 @@ define([
let parentElement = $(this);
let mapOverlayTimer = $('<div>', {
class: [config.mapOverlayClass, config.mapOverlayTimerClass].join(' ')
class: [MapOverlayUtil.config.mapOverlayClass, MapOverlayUtil.config.mapOverlayTimerClass].join(' ')
});
parentElement.append(mapOverlayTimer);
// ------------------------------------------------------------------------------------
parentElement.append(initZoomOverlay());
// --------------------------------------------------------------------------------------------------------
// add map overlay info. after scrollbar is initialized
let mapOverlayInfo = $('<div>', {
class: [config.mapOverlayClass, config.mapOverlayInfoClass].join(' ')
class: [MapOverlayUtil.config.mapOverlayClass, MapOverlayUtil.config.mapOverlayInfoClass].join(' ')
});
// add all overlay elements
@@ -758,12 +878,12 @@ define([
parentElement.append(mapOverlayInfo);
// reset map update timer
mapOverlayTimer.setMapUpdateCounter(100, config.logTimerCount);
setMapUpdateCounter(mapOverlayTimer, 100, MapOverlayUtil.config.logTimerCount);
});
};
return {
endpointOverlayId: config.endpointOverlayId
updateZoomOverlay: updateZoomOverlay,
initMapDebugOverlays: initMapDebugOverlays
};
});

View File

@@ -0,0 +1,97 @@
/**
* map overlay util functions
*/
define([
'jquery',
'app/init',
'app/util',
'app/map/util'
], ($, Init, Util) => {
'use strict';
let config = {
logTimerCount: 3, // map log timer in seconds
mapWrapperClass: 'pf-map-wrapper', // wrapper div (scrollable)
// map overlays sections
mapOverlayClass: 'pf-map-overlay', // class for all map overlays
mapOverlayTimerClass: 'pf-map-overlay-timer', // class for map overlay timer e.g. map timer
mapOverlayZoomClass: 'pf-map-overlay-zoom', // class for map overlay zoom
mapOverlayInfoClass: 'pf-map-overlay-info', // class for map overlay info e.g. map info
overlayLocalClass: 'pf-map-overlay-local', // class for map overlay "local" table
// system
systemHeadClass: 'pf-system-head', // class for system head
// connection overlay ids (they are not unique like CSS ids!)
connectionOverlayArrowId: 'pf-map-connection-arrow-overlay', // connection Arrows overlay ID (jsPlumb)
connectionOverlayWhId: 'pf-map-connection-wh-overlay', // connection WH overlay ID (jsPlumb)
connectionOverlayEolId: 'pf-map-connection-eol-overlay', // connection EOL overlay ID (jsPlumb)
debugOverlayId: 'pf-map-debug-overlay', // connection/endpoint overlay ID (jsPlumb)
endpointOverlayId: 'pf-map-endpoint-overlay', // endpoint overlay ID (jsPlumb)
// connection overlay classes classes
componentOverlayClass: 'pf-map-component-overlay', // class for "normal size" overlay
connectionArrowOverlaySuccessClass: 'pf-map-connection-arrow-overlay-success', // class for "success" arrow overlays
connectionArrowOverlayDangerClass: 'pf-map-connection-arrow-overlay-danger', // class for "danger" arrow overlays
// zoom overlay
zoomOverlayUpClass: 'pf-zoom-overlay-up',
zoomOverlayDownClass: 'pf-zoom-overlay-down',
zoomOverlayValueClass: 'pf-zoom-overlay-value'
};
/**
* get map overlay element by type e.g. timer/counter, info - overlay
* @param element
* @param overlayType
* @returns {null}
*/
let getMapOverlay = (element, overlayType) => {
let mapWrapperElement = $(element).parents('.' + config.mapWrapperClass);
let mapOverlay = null;
switch(overlayType){
case 'timer':
mapOverlay = mapWrapperElement.find('.' + config.mapOverlayTimerClass);
break;
case 'info':
mapOverlay = mapWrapperElement.find('.' + config.mapOverlayInfoClass);
break;
case 'zoom':
mapOverlay = mapWrapperElement.find('.' + config.mapOverlayZoomClass);
break;
case 'local':
mapOverlay = mapWrapperElement.find('.' + config.overlayLocalClass);
break;
}
return mapOverlay;
};
/**
* get the map counter chart from overlay
* @param element
* @returns {jQuery}
*/
let getMapCounter = element => $(element).find('.' + Init.classes.pieChart.pieChartMapCounterClass);
/**
* get interval value from map timer overlay
* @param element
* @returns {*}
*/
let getMapOverlayInterval = element => getMapCounter(getMapOverlay(element, 'timer')).data('interval');
return {
config: config,
getMapOverlay: getMapOverlay,
getMapCounter: getMapCounter,
getMapOverlayInterval: getMapOverlayInterval
};
});

View File

@@ -35,7 +35,7 @@ define([
advanced: {
updateOnContentResize: true,
autoExpandHorizontalScroll: true,
autoExpandHorizontalScroll: false, // on resize css scale() scroll content should not change
//autoExpandHorizontalScroll: 2,
autoScrollOnFocus: 'div',
},
@@ -72,25 +72,23 @@ define([
/**
* scroll to a specific position on map
* demo: http://manos.malihu.gr/repository/custom-scrollbar/demo/examples/scrollTo_demo.html
* @param scrollWrapper
* @param position
* @param options
*/
$.fn.scrollToPosition = function(position){
return this.each(function(){
$(this).mCustomScrollbar('scrollTo', position);
});
let scrollToPosition = (scrollWrapper, position, options) => {
$(scrollWrapper).mCustomScrollbar('scrollTo', position, options);
};
/**
* scroll to a specific system on map
* -> subtract some offset for tooltips/connections
* @param scrollWrapper
* @param position
* @returns {*}
*/
$.fn.scrollToSystem = function(position){
let scrollToSystem = (scrollWrapper, position) => {
position = getOffsetPosition(position, {x: -15, y: -35});
return this.each(function(){
$(this).mCustomScrollbar('scrollTo', position);
});
scrollToPosition(scrollWrapper, position);
};
/**
@@ -106,4 +104,9 @@ define([
y: Math.max(0, position.y + offset.y)
};
};
return {
scrollToPosition: scrollToPosition,
scrollToSystem: scrollToSystem
};
});

View File

@@ -5,13 +5,17 @@
define([
'jquery',
'app/init',
'app/util'
], ($, Init, Util) => {
'app/util',
'app/map/scrollbar',
'app/map/overlay/util'
], ($, Init, Util, Scrollbar, MapOverlayUtil) => {
'use strict';
let config = {
mapSnapToGridDimension: 20, // px for grid snapping (grid YxY)
defaultLocalJumpRadius: 3, // default search radius (in jumps) for "nearby" pilots
zoomMax: 1.5,
zoomMin: 0.5,
// local storage
characterLocalStoragePrefix: 'character_', // prefix for character data local storage key
@@ -53,8 +57,8 @@ define([
mapEndpoint : {
buttonId: Util.config.menuButtonEndpointId,
description: 'Endpoint overlay',
onEnable: 'showEndpointOverlays', // jQuery extension function
onDisable: 'hideEndpointOverlays' // jQuery extension function
onEnable: 'showInfoSignatureOverlays', // jQuery extension function
onDisable: 'hideInfoSignatureOverlays' // jQuery extension function
},
mapCompact : {
buttonId: Util.config.menuButtonCompactId,
@@ -312,7 +316,7 @@ define([
* @returns {*}
*/
let filterDefaultTypes = types => {
let defaultTypes = ['', 'default', 'state_active', 'state_process'];
let defaultTypes = ['', 'default', 'info_signature', 'state_active', 'state_process'];
return types.diff(defaultTypes);
};
@@ -434,7 +438,7 @@ define([
// remove connections from map
let removeConnections = connections => {
for(let connection of connections){
connection._jsPlumb.instance.detach(connection, {fireEvent: false});
connection._jsPlumb.instance.deleteConnection(connection, {fireEvent: false});
}
};
@@ -575,19 +579,15 @@ define([
*/
let getEndpointOverlaySignatureLocation = (endpoint, label) => {
let chars = label.length ? label.length : 2;
let xTop = chars === 2 ? +0.05 : chars <= 4 ? -0.75 : 3;
let xLeft = chars === 2 ? -1.10 : chars <= 4 ? -2.75 : 3;
let xRight = chars === 2 ? +1.25 : chars <= 4 ? +1.25 : 3;
let xBottom = chars === 2 ? +0.05 : chars <= 4 ? -0.75 : 3;
let xLeft = chars === 2 ? -0.5 : chars <= 4 ? -1 : 3;
let xRight = chars === 2 ? +1.5 : chars <= 4 ? +2.20 : 3;
let yTop = chars === 2 ? -1.10 : chars <= 4 ? -1.75 : 3;
switch(endpoint._continuousAnchorEdge){
case 'top': return [xTop, yTop];
case 'left': return [xLeft, 0];
case 'right': return [xRight, 0];
case 'bottom': return [xBottom , 1.3];
default: return [0.0, 0.0];
switch(endpoint.anchor.getCurrentFace()){
case 'top': return [0.5, -0.75];
case 'left': return [xLeft, 0.25];
case 'right': return [xRight, 0.25];
case 'bottom': return [0.5 , 1.75];
default: return [0.5, 0.5];
}
};
@@ -639,7 +639,6 @@ define([
*/
let filterMapByScopes = (map, scopes) => {
if(map){
// TODO ^^sometimes map is undefined -> bug
let mapElement = $(map.getContainer());
let allSystems = mapElement.getSystems();
let allConnections = map.getAllConnections();
@@ -684,7 +683,7 @@ define([
}
}
mapElement.getMapOverlay('info').updateOverlayIcon('filter', 'show');
MapOverlayUtil.getMapOverlay(mapElement, 'info').updateOverlayIcon('filter', 'show');
}else{
// clear filter
for(let system of allSystems){
@@ -694,11 +693,91 @@ define([
setConnectionVisible(connection, true);
}
mapElement.getMapOverlay('info').updateOverlayIcon('filter', 'hide');
MapOverlayUtil.getMapOverlay(mapElement, 'info').updateOverlayIcon('filter', 'hide');
}
}
};
/**
* in/de-crease zoom level
* @param map
* @param zoomAction
* @returns {boolean}
*/
let changeZoom = (map, zoomAction) => {
let zoomChange = false;
let zoom = map.getZoom();
let zoomStep = 0.1;
if('up' === zoomAction){
zoom += zoomStep;
}else{
zoom -= zoomStep;
}
zoom = Math.round(zoom * 10) / 10;
if(zoom >= config.zoomMin && zoom <= config.zoomMax){
zoomChange = setZoom(map, zoom);
}
return zoomChange;
};
/**
* set zoom level for a map
* @param map
* @param zoom
* @returns {boolean}
*/
let setZoom = (map, zoom = 1) => {
let zoomChange = false;
if(zoom !== map.getZoom()){
// zoom jsPlumb map http://jsplumb.github.io/jsplumb/zooming.html
let transformOrigin = [0, 0];
let el = map.getContainer();
let p = ['webkit', 'moz', 'ms', 'o'];
let s = 'scale(' + zoom + ')';
let oString = (transformOrigin[0] * 100) + '% ' + (transformOrigin[1] * 100) + '%';
for(let i = 0; i < p.length; i++){
el.style[p[i] + 'Transform'] = s;
el.style[p[i] + 'TransformOrigin'] = oString;
}
el.style.transform = s;
el.style.transformOrigin = oString;
zoomChange = map.setZoom(zoom);
// adjust mCustomScrollbar --------------------------------------------------------------------------------
let scaledWidth = el.getBoundingClientRect().width;
let scaledHeight = el.getBoundingClientRect().height;
let mapContainer = $(el);
let mapWidth = mapContainer.outerWidth(); // this is fix (should never change)
let mapHeight = mapContainer.outerHeight(); // this is fix (should never change)
let wrapperWidth = mapContainer.parents('.mCSB_container_wrapper').outerWidth(); // changes on browser resize (map window)
let wrapperHeight = mapContainer.parents('.mCSB_container_wrapper').outerHeight(); // changes on drag resize (map window)
let scrollableWidth = (zoom === 1 || mapWidth !== scaledWidth && scaledWidth > wrapperWidth);
let scrollableHeight = (zoom === 1 || mapHeight !== scaledHeight && scaledHeight > wrapperHeight);
mapContainer.parents('.mCSB_container').css({
'width': scrollableWidth ? scaledWidth + 'px' : (wrapperWidth - 50) + 'px',
'height': scrollableHeight ? scaledHeight + 'px' : (wrapperHeight) + 'px',
});
let mapWrapperElement = mapContainer.closest('.mCustomScrollbar');
if(scrollableWidth && scrollableHeight){
mapWrapperElement.mCustomScrollbar('update');
}else{
mapWrapperElement.mCustomScrollbar('scrollTo', '#pf-map-1', {
scrollInertia: 0,
scrollEasing: 'linear',
timeout: 0,
moveDragger: false
});
}
}
return zoomChange;
};
/**
* mark system as "selected" e.g. for dragging
* @param map
@@ -751,20 +830,96 @@ define([
system.toggleClass(config.systemHiddenClass, !visible);
};
/**
* add/remove connection type to connection that was previous registered by registerConnectionTypes()
* -> this method is a wrapper for addType()/removeType()
* with the addition of respecting active Arrow overlay direction
* @param action
* @param connection
* @param type
* @param params
* @param doNotRepaint
*/
let changeConnectionType = (action, connection, type, params = {}, doNotRepaint = false) => {
// check for active Arrow overlay
let overlayArrow, overlayArrowParams;
if(
type !== 'info_signature' &&
connection.hasType('info_signature')
){
overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
if(overlayArrow){
overlayArrowParams = {
direction: overlayArrow.direction,
foldback: overlayArrow.foldback,
};
}
}
// add the new type
connection[action](type, params, doNotRepaint);
// change Arrow overlay data back to initial direction
if(
overlayArrow &&
(
overlayArrow.direction !== overlayArrowParams.direction ||
overlayArrow.foldback !== overlayArrowParams.foldback
)
){
overlayArrow.updateFrom(overlayArrowParams);
if(!doNotRepaint){
connection.repaint();
}
}
};
/**
* add connection type to connection that was previous registered by registerConnectionTypes()
* @param connection
* @param type
* @param params
* @param doNotRepaint
*/
let addConnectionType = (connection, type, params = {}, doNotRepaint = false) => {
changeConnectionType('addType', connection, type, params, doNotRepaint);
};
/**
* remove connection type to connection that was previous registered by registerConnectionTypes()
* @param connection
* @param type
* @param params
* @param doNotRepaint
*/
let removeConnectionType = (connection, type, params = {}, doNotRepaint = false) => {
changeConnectionType('removeType', connection, type, params, doNotRepaint);
};
let toggleConnectionType = (connection, type, params = {}, doNotRepaint = false) => {
changeConnectionType('toggleType', connection, type, params, doNotRepaint);
};
/**
* mark a connection as "active"
* @param map
* @param connections
*/
let setConnectionsActive = (map, connections) => {
// set all inactive
for(let connection of getConnectionsByType(map, 'state_active')){
connection.removeType('state_active');
}
map.batch(() => {
// set all inactive
for(let connection of getConnectionsByType(map, 'state_active')){
if(!connections.includes(connection)){
removeConnectionType(connection, 'state_active');
}
}
for(let connection of connections){
connection.addType('state_active');
}
for(let connection of connections){
if(!connection.hasType('state_active')){
addConnectionType(connection, 'state_active');
}
}
});
};
/**
@@ -773,8 +928,11 @@ define([
* @param visible
*/
let setConnectionVisible = (connection, visible) => {
for(let endpoint of connection.endpoints){
endpoint.setVisible(visible);
if(connection.isVisible() !== visible){
connection.setVisible(visible, true);
for(let endpoint of connection.endpoints){
endpoint.setVisible(visible, true);
}
}
};
@@ -804,15 +962,18 @@ define([
let toggleConnectionActive = (map, connections) => {
let selectedConnections = [];
let deselectedConnections = [];
for(let connection of connections){
if(connection.hasType('state_active')){
connection.removeType('state_active');
deselectedConnections.push(connection);
}else{
connection.addType('state_active');
selectedConnections.push(connection);
map.batch(() => {
for(let connection of connections){
if(connection.hasType('state_active')){
removeConnectionType(connection, 'state_active');
deselectedConnections.push(connection);
}else{
addConnectionType(connection, 'state_active');
selectedConnections.push(connection);
}
}
}
});
updateConnectionInfo(map, selectedConnections, deselectedConnections);
};
@@ -1024,38 +1185,35 @@ define([
* @param {string} status
*/
let setConnectionWHStatus = (connection, status) => {
if(
status === 'wh_fresh' &&
connection.hasType('wh_fresh') !== true
){
connection.removeType('wh_reduced');
connection.removeType('wh_critical');
connection.addType('wh_fresh');
}else if(
status === 'wh_reduced' &&
connection.hasType('wh_reduced') !== true
){
connection.removeType('wh_fresh');
connection.removeType('wh_critical');
connection.addType('wh_reduced');
}else if(
status === 'wh_critical' &&
connection.hasType('wh_critical') !== true
){
connection.removeType('wh_fresh');
connection.removeType('wh_reduced');
connection.addType('wh_critical');
}else if(
status === 'wh_eol' &&
connection.hasType('wh_eol') !== true
){
connection.addType('wh_eol');
}else if(
status === 'wh_eol' &&
connection.hasType('wh_eol') !== true
){
connection.addType('wh_eol');
}
connection._jsPlumb.instance.batch(() => {
if(
status === 'wh_fresh' &&
connection.hasType('wh_fresh') !== true
){
removeConnectionType(connection, 'wh_reduced');
removeConnectionType(connection, 'wh_critical');
addConnectionType(connection, 'wh_fresh');
}else if(
status === 'wh_reduced' &&
connection.hasType('wh_reduced') !== true
){
removeConnectionType(connection, 'wh_fresh');
removeConnectionType(connection, 'wh_critical');
addConnectionType(connection, 'wh_reduced');
}else if(
status === 'wh_critical' &&
connection.hasType('wh_critical') !== true
){
removeConnectionType(connection, 'wh_fresh');
removeConnectionType(connection, 'wh_reduced');
addConnectionType(connection, 'wh_critical');
}else if(
status === 'wh_eol' &&
connection.hasType('wh_eol') !== true
){
addConnectionType(connection, 'wh_eol');
}
});
};
/**
@@ -1170,12 +1328,12 @@ define([
let visualizeMapExecutor = (resolve, reject) => {
// start map update counter -> prevent map updates during animations
mapElement.getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(mapElement, 'timer').startMapUpdateCounter();
let systemElements = mapElement.find('.' + config.systemClass);
let endpointElements = mapElement.find('.jsplumb-endpoint:visible');
let connectorElements = mapElement.find('.jsplumb-connector:visible');
let overlayElements = mapElement.find('.jsplumb-overlay:visible, .tooltip');
let endpointElements = mapElement.find('.jtk-endpoint:visible');
let connectorElements = mapElement.find('.jtk-connector:visible');
let overlayElements = mapElement.find('.jtk-overlay:visible, .tooltip');
let hideElements = (elements) => {
if(elements.length > 0){
@@ -1341,7 +1499,7 @@ define([
promiseStore.then(data => {
// This code runs once the value has been loaded from offline storage
if(data && data.scrollOffset){
mapWrapper.scrollToPosition([data.scrollOffset.y, data.scrollOffset.x]);
Scrollbar.scrollToPosition(mapWrapper, [data.scrollOffset.y, data.scrollOffset.x]);
}
resolve({
@@ -1404,7 +1562,7 @@ define([
if(rallyUpdated !== rally){
// rally status changed
if( !options.hideCounter ){
system.getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(system, 'timer').startMapUpdateCounter();
}
let rallyClass = getInfoForSystem('rally', 'class');
@@ -1812,11 +1970,13 @@ define([
markAsChanged: markAsChanged,
hasChanged: hasChanged,
toggleSystemsSelect: toggleSystemsSelect,
toggleConnectionType: toggleConnectionType,
toggleConnectionActive: toggleConnectionActive,
setSystemActive: setSystemActive,
showSystemInfo: showSystemInfo,
showConnectionInfo: showConnectionInfo,
showFindRouteDialog: showFindRouteDialog,
filterDefaultTypes: filterDefaultTypes,
getEndpointLabel: getEndpointLabel,
getConnectionsByType: getConnectionsByType,
getEndpointsDataByConnection: getEndpointsDataByConnection,
@@ -1837,6 +1997,8 @@ define([
getTabContentElementByMapElement: getTabContentElementByMapElement,
hasActiveConnection: hasActiveConnection,
filterMapByScopes: filterMapByScopes,
changeZoom: changeZoom,
setZoom: setZoom,
storeLocaleCharacterData: storeLocaleCharacterData,
getLocaleData: getLocaleData,
storeLocalData: storeLocalData,

View File

@@ -322,7 +322,7 @@ define([
}),
getMenuHeadline('Configuration'),
$('<a>', {
class: 'list-group-item',
class: ['list-group-item', 'loading'].join(' '),
html: '&nbsp;&nbsp;Settings'
}).prepend(
$('<i>',{
@@ -332,7 +332,7 @@ define([
$(document).triggerMenuEvent('ShowMapSettings', {tab: 'settings'});
}),
$('<a>', {
class: 'list-group-item',
class: ['list-group-item', 'loading'].join(' '),
id: Util.config.menuButtonGridId,
html:'&nbsp;&nbsp;Grid snapping'
}).prepend(
@@ -346,7 +346,7 @@ define([
});
}),
$('<a>', {
class: 'list-group-item',
class: ['list-group-item', 'loading'].join(' '),
id: Util.config.menuButtonMagnetizerId,
html: '&nbsp;&nbsp;Magnetizing'
}).prepend(
@@ -360,7 +360,7 @@ define([
});
}),
$('<a>', {
class: 'list-group-item',
class: ['list-group-item', 'loading'].join(' '),
id: Util.config.menuButtonEndpointId,
html: '&nbsp;&nbsp;Signatures'
}).prepend(
@@ -374,18 +374,13 @@ define([
});
}),
$('<a>', {
class: 'list-group-item',
class: ['list-group-item', 'loading'].join(' '),
id: Util.config.menuButtonCompactId,
html: '&nbsp;&nbsp;Compact'
}).prepend(
$('<i>',{
class: 'fas fa-compress fa-fw'
})
).append(
$('<span>',{
class: 'badge bg-color bg-color-gray txt-color txt-color-warning',
text: 'beta'
})
).on('click', function(){
Util.getMapModule().getActiveMap().triggerMenuEvent('MapOption', {
option: 'mapCompact',
@@ -743,6 +738,10 @@ define([
documentElement.on('pf:updateMenuOptions', function(e, data){
let hasRightMapDelete = MapUtil.checkRight('map_delete', data.mapConfig);
$('#' + Util.config.menuButtonMapDeleteId).toggleClass('disabled', !hasRightMapDelete);
// "loading" menu options require an active map
// -> active map now available -> remove loading class
$('.' + config.pageMenuRightClass + ' .loading').removeClass('loading');
});
// update header links with current map data
@@ -1311,5 +1310,4 @@ define([
initTabChangeObserver: initTabChangeObserver,
renderMapContextMenus: renderMapContextMenus
};
});

View File

@@ -62,23 +62,17 @@ define([
let disableOnScrollEvent = false;
// scroll breakpoints
let scrolLBreakpointElements = null;
let scrollBreakpointElements = $('.pf-manual-scroll-break');
// scroll navigation links
let scrollNavLiElements = null;
mapManualDialog.on('shown.bs.modal', function(e){
// modal on open
scrolLBreakpointElements = $('.pf-manual-scroll-break');
scrollNavLiElements = $('.' + config.dialogNavigationListItemClass);
});
let scrollNavLiElements = $('.' + config.dialogNavigationListItemClass);
let scrollspyElement = $('#' + config.mapManualScrollspyId);
let whileScrolling = function(){
if(disableOnScrollEvent === false){
for(let i = 0; i < scrolLBreakpointElements.length; i++){
let offset = $(scrolLBreakpointElements[i]).offset().top;
for(let i = 0; i < scrollBreakpointElements.length; i++){
let offset = $(scrollBreakpointElements[i]).offset().top;
if( (offset - modalOffsetTop) > 0){

View File

@@ -3056,6 +3056,18 @@ define([
*/
let isDomElement = obj => !!(obj && obj.nodeType === 1);
/**
* converts array of objects into object with properties
* @param array
* @param keyField
* @returns {*}
*/
let arrayToObject = (array, keyField = 'id') =>
array.reduce((obj, item) => {
obj[item[keyField]] = item;
return obj;
}, {});
/**
* get deep json object value if exists
* -> e.g. key = 'first.last.third' string
@@ -3262,6 +3274,7 @@ define([
htmlDecode: htmlDecode,
isValidHtml: isValidHtml,
isDomElement: isDomElement,
arrayToObject: arrayToObject,
getObjVal: getObjVal,
redirect: redirect,
logout: logout,

File diff suppressed because it is too large Load Diff

View File

@@ -77,13 +77,14 @@ $.fn.dragToSelect = function (conf) {
// deselected items
var deselectedItems = $();
/*
do {
if (/auto|scroll|hidden/.test(parent.css('overflow'))) {
break;
}
parent = parent.parent();
} while (parent[0].parentNode);
*/
// Does user want to disable dragToSelect
if (conf == 'disable') {
parent.addClass(config.disabledClass);
@@ -133,8 +134,8 @@ $.fn.dragToSelect = function (conf) {
return;
}
selectBoxOrigin.left = e.pageX - parentDim.left + parent[0].scrollLeft - 5;
selectBoxOrigin.top = e.pageY - parentDim.top + parent[0].scrollTop - 5;
selectBoxOrigin.left = e.pageX - parentDim.left + parent[0].scrollLeft;
selectBoxOrigin.top = e.pageY - parentDim.top + parent[0].scrollTop;
var css = {
left: selectBoxOrigin.left + 'px',
@@ -342,7 +343,7 @@ $.fn.dragToSelect = function (conf) {
}
var mouseupCallback = function(){
if (config.selectables){
if(config.selectables){
selectElementsInRange();
}
hideSelectBox();
@@ -364,10 +365,10 @@ $.fn.dragToSelect = function (conf) {
}).mouseup(mouseupCallback);
parent.mousedown(function(e){
if (
if(
e.which === 1 && // left mouse down
e.target === realParent[0] // prevent while dragging a system :)
) {
){
// Make sure user isn't clicking scrollbar (or disallow clicks far to the right actually)
if ((e.pageX + 20) > $(document.body).width()) {
return;
@@ -386,7 +387,6 @@ $.fn.dragToSelect = function (conf) {
e.preventDefault();
}).mouseup(mouseupCallback);
// Be nice
return this;
};

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -33,7 +33,7 @@ requirejs.config({
velocity: 'lib/velocity.min', // v1.5.1 animation engine - http://julian.com/research/velocity
velocityUI: 'lib/velocity.ui.min', // v5.2.0 plugin for velocity - http://julian.com/research/velocity/#uiPack
slidebars: 'lib/slidebars', // v2.0.2 Slidebars - side menu plugin https://www.adchsm.com/slidebars/
jsPlumb: 'lib/dom.jsPlumb-1.7.6', // v1.7.6 jsPlumb (Vanilla)- main map draw plugin https://jsplumbtoolkit.com
jsPlumb: 'lib/jsplumb', // v2.9.3 jsPlumb main map draw plugin http://jsplumb.github.io/jsplumb/home.html
farahey: 'lib/farahey-0.5', // v0.5 jsPlumb "magnetizing" extension - https://github.com/jsplumb/farahey
customScrollbar: 'lib/jquery.mCustomScrollbar.min', // v3.1.5 Custom scroll bars - http://manos.malihu.gr
mousewheel: 'lib/jquery.mousewheel.min', // v3.1.13 Mousewheel - https://github.com/jquery/jquery-mousewheel

View File

@@ -343,51 +343,53 @@ define(['jquery'], ($) => {
}
},
wh_eol: {
cssClass: 'pf-map-connection-wh-eol',
paintStyle: {
dashstyle: '0' // solid line
}
cssClass: 'pf-map-connection-wh-eol'
},
wh_fresh: {
cssClass: 'pf-map-connection-wh-fresh',
paintStyle: {
dashstyle: '0' // solid line
}
cssClass: 'pf-map-connection-wh-fresh'
},
wh_reduced: {
cssClass: 'pf-map-connection-wh-reduced',
paintStyle: {
dashstyle: '0' // solid line
}
cssClass: 'pf-map-connection-wh-reduced'
},
wh_critical: {
cssClass: 'pf-map-connection-wh-critical',
paintStyle: {
dashstyle: '0' // solid line
}
cssClass: 'pf-map-connection-wh-critical'
},
frigate: {
cssClass: 'pf-map-connection-frig',
paintStyle: {
dashstyle: '0.99'
dashstyle: '0.5 1'
},
overlays:[
overlays: [
['Label',
{
label: 'frig',
cssClass: ['pf-map-component-overlay', 'frig'].join(' '),
location: 0.6
location: 0.7
}]
]
},
preserve_mass: {
cssClass: 'pf-map-connection-preserve-mass',
overlays:[
overlays: [
['Label',
{
label: '<i class="fas fa-fw fa-exclamation-triangle"></i>&nbsp;save mass',
cssClass: ['pf-map-component-overlay', 'mass'].join(' '),
location: 0.6
location: 0.3
}]
]
},
info_signature: {
overlays: [
['Arrow',
{
id: 'pf-map-connection-arrow-overlay',
cssClass: 'pf-map-connection-arrow-overlay',
width: 12,
length: 15,
foldback: 0.8,
direction: 1,
location: 0.5
}]
]
},
@@ -396,12 +398,12 @@ define(['jquery'], ($) => {
},
state_process: {
cssClass: 'pf-map-connection-process',
overlays:[
overlays: [
['Label',
{
label: '<i class="fas fa-fw fa-sync fa-spin"></i>',
cssClass: ['pf-map-connection-state-overlay'].join(' '),
location: 0.6
location: 0.5
}]
]
}

View File

@@ -10,6 +10,12 @@ define([
label: 'Close open dialog',
keyNames: ['ESC']
},
// map ----------------------------------------------------------------------------------------------
mapMove: {
group: 'map',
label: 'Move map section',
keyNames: ['drag', 'move']
},
// signature ----------------------------------------------------------------------------------------
signatureSelect: {
group: 'signatures',
@@ -79,12 +85,6 @@ define([
*/
let debug = false;
/**
* check interval for "new" active keys
* @type {number}
*/
let keyWatchPeriod = 100;
/**
* DOM data key for an element that lists all active events (comma separated)
* @type {string}
@@ -133,6 +133,13 @@ define([
return Object.keys(map);
};
/**
* checks whether a key is currently active (keydown)
* @param key
* @returns {boolean}
*/
let isActive = key => map.hasOwnProperty(key) && map[key] === true;
/**
* callback function that compares two arrays
* @param element
@@ -460,6 +467,7 @@ define([
};
return {
isActive: isActive,
getGroupedShortcuts: getGroupedShortcuts
};
});

View File

@@ -6,17 +6,19 @@ define([
'jquery',
'app/init',
'app/util',
'app/key',
'bootbox',
'app/map/util',
'app/map/contextmenu',
'app/map/overlay',
'app/map/overlay/overlay',
'app/map/overlay/util',
'app/map/system',
'app/map/layout',
'app/map/magnetizing',
'app/map/scrollbar',
'dragToSelect',
'app/map/local'
], ($, Init, Util, bootbox, MapUtil, MapContextMenu, MapOverlay, System, Layout, MagnetizerWrapper) => {
], ($, Init, Util, Key, bootbox, MapUtil, MapContextMenu, MapOverlay, MapOverlayUtil, System, Layout, MagnetizerWrapper, Scrollbar) => {
'use strict';
@@ -91,8 +93,7 @@ define([
},
connectionsDetachable: true, // dragOptions are set -> allow detaching them
maxConnections: 10, // due to isTarget is true, this is the max count of !out!-going connections
// isSource:true,
anchor: 'Continuous'
// isSource:true
},
target: {
filter: filterSystemHeadEvent,
@@ -104,9 +105,7 @@ define([
hoverClass: config.systemActiveClass,
activeClass: 'dragActive'
},
// isTarget:true,
// uniqueEndpoint: false,
anchor: 'Continuous'
// uniqueEndpoint: false
},
endpointTypes: Init.endpointTypes,
connectionTypes: Init.connectionTypes
@@ -130,7 +129,7 @@ define([
// -> we need BOTH endpoints of a connection -> index 0
for(let endpoint of connectionInfo[0].endpoints){
// check if there is a Label overlay
let overlay = endpoint.getOverlay(MapOverlay.endpointOverlayId);
let overlay = endpoint.getOverlay(MapOverlayUtil.config.endpointOverlayId);
if(overlay instanceof jsPlumb.Overlays.Label){
let label = overlay.getParameter('label');
overlay.setLocation(MapUtil.getEndpointOverlaySignatureLocation(endpoint, label));
@@ -588,7 +587,7 @@ define([
case 'change_status_empty':
case 'change_status_unscanned':
// change system status
system.getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(system, 'timer').startMapUpdateCounter();
let statusString = action.split('_');
@@ -730,16 +729,15 @@ define([
case 'frigate': // set as frigate hole
case 'preserve_mass': // set "preserve mass
case 'wh_eol': // set "end of life"
mapElement.getMapOverlay('timer').startMapUpdateCounter();
connection.toggleType(action);
MapOverlayUtil.getMapOverlay(mapElement, 'timer').startMapUpdateCounter();
MapUtil.toggleConnectionType(connection, action);
MapUtil.markAsChanged(connection);
break;
case 'status_fresh':
case 'status_reduced':
case 'status_critical':
let newStatus = action.split('_')[1];
mapElement.getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(mapElement, 'timer').startMapUpdateCounter();
MapUtil.setConnectionWHStatus(connection, 'wh_' + newStatus);
MapUtil.markAsChanged(connection);
break;
@@ -751,7 +749,7 @@ define([
bootbox.confirm('Change scope from ' + scopeName + ' to ' + newScopeName + '?', function(result){
if(result){
mapElement.getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(mapElement, 'timer').startMapUpdateCounter();
setConnectionScope(connection, newScope);
@@ -775,7 +773,7 @@ define([
switch(action){
case 'bubble':
mapElement.getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(mapElement, 'timer').startMapUpdateCounter();
endpoint.toggleType(action);
for(let connection of endpoint.connections){
@@ -860,7 +858,7 @@ define([
source: sourceSystem[0],
target: targetSystem[0],
scope: connectionData.scope || map.Defaults.Scope,
type: (connectionData.type || MapUtil.getDefaultConnectionTypeByScope(map.Defaults.Scope)).join(' ')
//type: (connectionData.type || MapUtil.getDefaultConnectionTypeByScope(map.Defaults.Scope)).join(' ')
/* experimental set "static" connection parameters in initial load
parameters: {
connectionId: connectionId,
@@ -878,6 +876,7 @@ define([
// check if connection is valid (e.g. source/target exist
if(connection instanceof jsPlumb.Connection){
connection.addType((connectionData.type || MapUtil.getDefaultConnectionTypeByScope(map.Defaults.Scope)).join(' '));
// set connection parameters
// they should persist even through connection type change (e.g. wh -> stargate,..)
@@ -1145,7 +1144,7 @@ define([
mapWrapper.setMapShortcuts();
// show static overlay actions
let mapOverlay = mapContainer.getMapOverlay('info');
let mapOverlay = MapOverlayUtil.getMapOverlay(mapContainer, 'info');
mapOverlay.updateOverlayIcon('systemRegion', 'show');
mapOverlay.updateOverlayIcon('connection', 'show');
mapOverlay.updateOverlayIcon('connectionEol', 'show');
@@ -1316,7 +1315,7 @@ define([
deleteConnection.source &&
deleteConnection.target
){
mapConfig.map.detach(deleteConnection, {fireEvent: false});
mapConfig.map.deleteConnection(deleteConnection, {fireEvent: false});
}
}
}
@@ -1626,12 +1625,12 @@ define([
Util.showNotify({title: title, text: 'Scope: ' + scope, type: 'success'});
}else{
// some save errors
payload.context.map.detach(payload.context.connection, {fireEvent: false});
payload.context.map.deleteConnection(payload.context.connection, {fireEvent: false});
}
},
payload => {
// remove this connection from map
payload.context.map.detach(payload.context.connection, {fireEvent: false});
payload.context.map.deleteConnection(payload.context.connection, {fireEvent: false});
Util.handleAjaxErrorResponse(payload);
}
);
@@ -1830,7 +1829,7 @@ define([
start: function(params){
let dragSystem = $(params.el);
mapOverlayTimer = dragSystem.getMapOverlay('timer');
mapOverlayTimer = MapOverlayUtil.getMapOverlay(dragSystem, 'timer');
// start map update timer
mapOverlayTimer.startMapUpdateCounter();
@@ -2047,7 +2046,7 @@ define([
revalidate(map, system);
if(!hideCounter){
$(system).getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(system, 'timer').startMapUpdateCounter();
}
};
@@ -2063,18 +2062,33 @@ define([
jsPlumb.Defaults.LogEnabled = true;
let newJsPlumbInstance = jsPlumb.getInstance({
Anchor: 'Continuous', // anchors on each site
Container: null, // will be set as soon as container is connected to DOM
Anchor: ['Continuous', {faces: ['top', 'right', 'bottom', 'left']}], // single anchor (used during drag action)
Anchors: [
['Continuous', {faces: ['top', 'right', 'bottom', 'left']}],
['Continuous', {faces: ['top', 'right', 'bottom', 'left']}],
],
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.
strokeWidth: 4, // connection width (inner)
stroke: '#3c3f41', // connection color (inner)
outlineWidth: 2, // connection width (outer)
outlineStroke: '#63676a', // connection color (outer)
dashstyle: '0', // connection dashstyle (default) -> is used after connectionType got removed that has dashstyle specified
'stroke-linecap': 'round' // connection shape
},
Connector: [ 'Bezier', { curviness: 40 } ], // default connector style (this is not used!) all connections have their own style (by scope)
Endpoint: [ 'Dot', { radius: 5 } ],
ReattachConnections: false, // re-attach connection if dragged with mouse to "nowhere"
Scope: Init.defaultMapScope, // default map scope for connections
Endpoint: ['Dot', {radius: 5}], // single endpoint (used during drag action)
Endpoints: [
['Dot', {radius: 5, cssClass: config.endpointSourceClass}],
['Dot', {radius: 5, cssClass: config.endpointTargetClass}]
],
EndpointStyle: {fill: '#3c3f41', stroke: '#63676a', strokeWidth: 2}, // single endpoint style (used during drag action)
EndpointStyles: [
{fill: '#3c3f41', stroke: '#63676a', strokeWidth: 2},
{fill: '#3c3f41', stroke: '#63676a', strokeWidth: 2}
],
Connector: ['Bezier', {curviness: 40}], // default connector style (this is not used!) all connections have their own style (by scope)
ReattachConnections: false, // re-attach connection if dragged with mouse to "nowhere"
Scope: Init.defaultMapScope, // default map scope for connections
LogEnabled: true
});
@@ -2181,6 +2195,13 @@ define([
});
// Notification an existing Connection is being dragged.
// Note that when this event fires for a brand new Connection, the target of the Connection is a transient element
// that jsPlumb is using for dragging, and will be removed from the DOM when the Connection is subsequently either established or aborted.
newJsPlumbInstance.bind('connectionDrag', function(info, e){
});
// Notification a Connection was detached.
// In the event that the Connection was new and had never been established between two Endpoints, it has a pending flag set on it.
newJsPlumbInstance.bind('connectionDetached', function(info, e){
@@ -2200,6 +2221,11 @@ define([
});
// Notification the current zoom was changed
newJsPlumbInstance.bind('zoom', function(zoom){
MapOverlay.updateZoomOverlay(this);
});
// ========================================================================================================
// Events for interactive CSS classes https://community.jsplumbtoolkit.com/doc/styling-via-css.html
//=========================================================================================================
@@ -2276,6 +2302,8 @@ define([
// get map container
let mapContainer = $(map.getContainer());
MapOverlay.initMapDebugOverlays(map);
// context menu for mapContainer
mapContainer.on('contextmenu', function(e){
e.preventDefault();
@@ -2472,14 +2500,14 @@ define([
// toggle "fullSize" Endpoint overlays for system (signature information) -------------------------------------
mapContainer.hoverIntent({
over: function(e){
for(let overlayInfo of map.selectEndpoints({element: this}).getOverlay(MapOverlay.endpointOverlayId)){
for(let overlayInfo of map.selectEndpoints({element: this}).getOverlay(MapOverlayUtil.config.endpointOverlayId)){
if(overlayInfo[0] instanceof jsPlumb.Overlays.Label){
overlayInfo[0].fire('toggleSize', true);
}
}
},
out: function(e){
for(let overlayInfo of map.selectEndpoints({element: this}).getOverlay(MapOverlay.endpointOverlayId)){
for(let overlayInfo of map.selectEndpoints({element: this}).getOverlay(MapOverlayUtil.config.endpointOverlayId)){
if(overlayInfo[0] instanceof jsPlumb.Overlays.Label){
overlayInfo[0].fire('toggleSize', false);
}
@@ -2526,7 +2554,7 @@ define([
}
// show map overlay info icon
this.mapElement.getMapOverlay('info').updateOverlayIcon(this.mapOption.option, 'hide');
MapOverlayUtil.getMapOverlay(this.mapElement, 'info').updateOverlayIcon(this.mapOption.option, 'hide');
// delete map option
MapUtil.deleteLocalData('map', this.mapElement.data('id'), this.mapOption.option );
@@ -2545,7 +2573,7 @@ define([
}
// hide map overlay info icon
this.mapElement.getMapOverlay('info').updateOverlayIcon(this.mapOption.option, 'show');
MapOverlayUtil.getMapOverlay(this.mapElement, 'info').updateOverlayIcon(this.mapOption.option, 'show');
// store map option
MapUtil.storeLocalData('map', this.mapElement.data('id'), this.mapOption.option, 1 );
@@ -2591,7 +2619,7 @@ define([
if(select){
let mapWrapper = mapElement.closest('.' + config.mapWrapperClass);
mapWrapper.scrollToSystem(MapUtil.getSystemPosition(system));
Scrollbar.scrollToSystem(mapWrapper, MapUtil.getSystemPosition(system));
// select system
MapUtil.showSystemInfo(map, system);
}
@@ -2622,7 +2650,7 @@ define([
// update "local" overlay for this map
mapContainer.on('pf:updateLocal', function(e, userData){
let mapElement = $(this);
let mapOverlay = mapElement.getMapOverlay('local');
let mapOverlay = MapOverlayUtil.getMapOverlay(mapElement, 'local');
if(userData && userData.config && userData.config.id){
let currentMapData = Util.getCurrentMapData(userData.config.id);
@@ -2826,7 +2854,7 @@ define([
let getMapDataForSync = (mapContainer, filter = [], minimal = false) => {
let mapData = false;
// check if there is an active map counter that prevents collecting map data (locked map)
if(!mapContainer.getMapOverlayInterval()){
if(!MapOverlayUtil.getMapOverlayInterval(mapContainer)){
mapData = mapContainer.getMapDataFromClient(filter, minimal);
}
return mapData;
@@ -3044,6 +3072,96 @@ define([
mapWrapperElement.initCustomScrollbar({
callbacks: {
onInit: function(){
// init 'space' key + 'mouse' down for map scroll -------------------------------------------------
let scrollStart = [0, 0];
let mouseStart = [0, 0];
let mouseOffset = [0, 0];
let animationFrameId = 0;
let toggleDragScroll = active => {
mapElement.toggleClass('disabled', active).toggleClass(' pf-map-move', active);
};
let stopDragScroll = () => {
cancelAnimationFrame(animationFrameId);
animationFrameId = 0;
scrollStart = [0, 0];
mouseStart = [0, 0];
mouseOffset = [0, 0];
};
let dragScroll = () => {
if(Key.isActive(' ')){
let scrollOffset = [
Math.max(0, scrollStart[0] - mouseOffset[0]),
Math.max(0, scrollStart[1] - mouseOffset[1])
];
if(
scrollOffset[0] !== Math.abs(this.mcs.left) ||
scrollOffset[1] !== Math.abs(this.mcs.top)
){
Scrollbar.scrollToPosition(this, [scrollOffset[1], scrollOffset[0]], {
scrollInertia: 0,
scrollEasing: 'linear',
timeout: 5
});
}
// recursive re-call on next render
animationFrameId = requestAnimationFrame(dragScroll);
}
};
let keyDownHandler = function(e){
if(e.keyCode === 32){
e.preventDefault();
toggleDragScroll(true);
}
};
let keyUpHandler = function(e){
if(e.keyCode === 32){
e.preventDefault();
toggleDragScroll(false);
}
};
let mouseMoveHandler = function(e){
if(animationFrameId){
mouseOffset[0] = e.clientX - mouseStart[0];
mouseOffset[1] = e.clientY - mouseStart[1];
}
// space activated on mouse move
toggleDragScroll(Key.isActive(' '));
};
let mouseDownHandler = function(e){
if(!animationFrameId && e.which === 1 && Key.isActive(' ')){
scrollStart[0] = Math.abs(this.mcs.left);
scrollStart[1] = Math.abs(this.mcs.top);
mouseStart[0] = e.clientX;
mouseStart[1] = e.clientY;
toggleDragScroll(true);
animationFrameId = requestAnimationFrame(dragScroll);
}
};
let mouseUpHandler = function(e){
if(e.which === 1){
stopDragScroll();
}
};
this.addEventListener('keydown', keyDownHandler, { capture: false });
this.addEventListener('keyup', keyUpHandler, { capture: false });
this.addEventListener('mousemove', mouseMoveHandler, { capture: false });
this.addEventListener('mousedown', mouseDownHandler, { capture: false });
this.addEventListener('mouseup', mouseUpHandler, { capture: false });
},
onScroll: function(){
// scroll complete
// update scroll position for drag-frame-selection
@@ -3070,7 +3188,6 @@ define([
// add map overlays after scrollbar is initialized
// because of its absolute position
mapWrapperElement.initMapOverlays();
mapWrapperElement.initLocalOverlay(mapId);
};

View File

@@ -6,36 +6,11 @@ define([
'jquery',
'app/init',
'app/util',
'app/map/overlay/util',
'app/map/util'
], ($, Init, Util, MapUtil) => {
], ($, Init, Util, MapOverlayUtil, MapUtil) => {
'use strict';
let config = {
logTimerCount: 3, // map log timer in seconds
// map overlay positions
mapOverlayClass: 'pf-map-overlay', // class for all map overlays
mapOverlayTimerClass: 'pf-map-overlay-timer', // class for map overlay timer e.g. map timer
mapOverlayInfoClass: 'pf-map-overlay-info', // class for map overlay info e.g. map info
overlayLocalClass: 'pf-map-overlay-local', // class for map overlay "local" table
// system
systemHeadClass: 'pf-system-head', // class for system head
// overlay IDs
connectionOverlayWhId: 'pf-map-connection-wh-overlay', // connection WH overlay ID (jsPlumb)
connectionOverlayEolId: 'pf-map-connection-eol-overlay', // connection EOL overlay ID (jsPlumb)
connectionOverlayArrowId: 'pf-map-connection-arrow-overlay', // connection Arrows overlay ID (jsPlumb)
endpointOverlayId: 'pf-map-endpoint-overlay', // endpoint overlay ID (jsPlumb)
// overlay classes
componentOverlayClass: 'pf-map-component-overlay', // class for "normal size" overlay
connectionArrowOverlayClass: 'pf-map-connection-arrow-overlay', // class for "connection arrow" overlay
connectionDiamondOverlayClass: 'pf-map-connection-diamond-overlay' // class for "connection diamond" overlay
};
/**
* get MapObject (jsPlumb) from mapElement
* @param mapElement
@@ -43,7 +18,7 @@ define([
*/
let getMapObjectFromMapElement = mapElement => {
let Map = require('app/map/map');
return Map.getMapInstance( mapElement.data('id') );
return Map.getMapInstance(mapElement.data('id'));
};
/**
@@ -53,8 +28,7 @@ define([
*/
let getMapObjectFromOverlayIcon = overlayIcon => {
let mapElement = Util.getMapElementFromOverlay(overlayIcon);
return getMapObjectFromMapElement( mapElement );
return getMapObjectFromMapElement(mapElement);
};
/**
@@ -65,127 +39,164 @@ define([
let addEndpointOverlaySignatureLabel = (endpoint, labelData) => {
let label = labelData.labels.join(', ');
let name = labelData.names.join(', ');
let overlay = endpoint.getOverlay(MapOverlayUtil.config.endpointOverlayId);
endpoint.addOverlay([
'Label',
{
label: MapUtil.formatEndpointOverlaySignatureLabel(label),
id: config.endpointOverlayId,
cssClass: [config.componentOverlayClass, label.length ? 'small' : 'icon'].join(' '),
location: MapUtil.getEndpointOverlaySignatureLocation(endpoint, label),
events: {
toggleSize: function(fullSize){
let signatureName = this.getParameter('signatureName');
if(fullSize && !this.getParameter('fullSize') && signatureName){
this.setLabel(this.getLabel() + '<br>' + '<span class="initialism">' + signatureName + '</span>');
this.setParameter('fullSize', true);
}else if(this.getParameter('fullSize')){
this.setLabel(MapUtil.formatEndpointOverlaySignatureLabel(this.getParameter('label')));
this.setParameter('fullSize', false);
}
}
},
parameters: {
fullSize: false,
label: label,
signatureName: name
}
}
]);
};
/**
* add overlays to connections (signature based data)
* @param connections
* @param connectionsData
*/
let addConnectionsOverlay = (connections, connectionsData) => {
let SystemSignatures = require('app/ui/module/system_signature');
// loop through all map connections (get from DOM)
for(let connection of connections){
let connectionId = connection.getParameter('connectionId');
let sourceEndpoint = connection.endpoints[0];
let targetEndpoint = connection.endpoints[1];
let signatureTypeData = {
source: {
names: [],
labels: []
},
target: {
names: [],
labels: []
}
};
// ... find matching connectionData (from Ajax)
for(let connectionData of connectionsData){
if(connectionData.id === connectionId){
signatureTypeData = MapUtil.getConnectionDataFromSignatures(connection, connectionData);
// ... connection matched -> continue with next one
break;
}
}
// add endpoint overlays ------------------------------------------------------
addEndpointOverlaySignatureLabel(sourceEndpoint, signatureTypeData.source);
addEndpointOverlaySignatureLabel(targetEndpoint, signatureTypeData.target);
let sourceLabel = signatureTypeData.source.labels;
let targetLabel = signatureTypeData.target.labels;
// add arrow (connection) overlay that points from "XXX" => "K162" ------------
let overlayType = 'Diamond'; // not specified
let arrowDirection = 1;
if(overlay instanceof jsPlumb.Overlays.Label){
// update existing overlay
if(
(sourceLabel.indexOf('K162') !== -1 && targetLabel.indexOf('K162') !== -1) ||
(sourceLabel.length === 0 && targetLabel.length === 0) ||
(
sourceLabel.length > 0 && targetLabel.length > 0 &&
sourceLabel.indexOf('K162') === -1 && targetLabel.indexOf('K162') === -1
)
label !== overlay.getParameter('label') ||
name !== overlay.getParameter('signatureName')
){
// unknown direction
overlayType = 'Diamond'; // not specified
arrowDirection = 1;
}else if(
(sourceLabel.indexOf('K162') !== -1) ||
(sourceLabel.length === 0 && targetLabel.indexOf('K162') === -1)
){
// convert default arrow direction
overlayType = 'Arrow';
arrowDirection = -1;
}else{
// default arrow direction is fine
overlayType = 'Arrow';
arrowDirection = 1;
// update label only on label changes
overlay.setLabel(MapUtil.formatEndpointOverlaySignatureLabel(label));
overlay.setParameter('fullSize', false);
overlay.setParameter('label', label);
overlay.setParameter('signatureName', name);
overlay.updateClasses(label.length ? 'small' : 'icon', label.length ? 'icon' : 'small');
overlay.setLocation(MapUtil.getEndpointOverlaySignatureLocation(endpoint, label));
}
connection.addOverlay([
overlayType,
}else{
// add new overlay
endpoint.addOverlay([
'Label',
{
width: 12,
length: 15,
location: 0.5,
foldback: 0.85,
direction: arrowDirection,
id: config.connectionOverlayArrowId,
cssClass: (overlayType === 'Arrow') ? config.connectionArrowOverlayClass : config.connectionDiamondOverlayClass
label: MapUtil.formatEndpointOverlaySignatureLabel(label),
id: MapOverlayUtil.config.endpointOverlayId,
cssClass: [MapOverlayUtil.config.componentOverlayClass, label.length ? 'small' : 'icon'].join(' '),
location: MapUtil.getEndpointOverlaySignatureLocation(endpoint, label),
events: {
toggleSize: function(fullSize){
let signatureName = this.getParameter('signatureName');
if(fullSize && !this.getParameter('fullSize') && signatureName){
this.setLabel(this.getLabel() + '<br>' + '<span class="initialism">' + signatureName + '</span>');
this.setParameter('fullSize', true);
}else if(this.getParameter('fullSize')){
this.setLabel(MapUtil.formatEndpointOverlaySignatureLabel(this.getParameter('label')));
this.setParameter('fullSize', false);
}
}
},
parameters: {
fullSize: false,
label: label,
signatureName: name
}
}
]);
}
};
/**
* remove overviews from a Tooltip
* @param endpoint
* @param i
* add overlays to connections (signature based data)
* @param map
* @param connectionsData
*/
let removeEndpointOverlay = (endpoint, i) => {
endpoint.removeOverlays(config.endpointOverlayId);
let updateInfoSignatureOverlays = (map, connectionsData) => {
let type = 'info_signature';
let SystemSignatures = require('app/ui/module/system_signature');
connectionsData = Util.arrayToObject(connectionsData);
map.batch(function(){
map.getAllConnections().forEach(function(connection){
let connectionId = connection.getParameter('connectionId');
let sourceEndpoint = connection.endpoints[0];
let targetEndpoint = connection.endpoints[1];
let signatureTypeData = {
source: {
names: [],
labels: []
},
target: {
names: [],
labels: []
}
};
if(connection.scope === 'wh'){
if(!connection.hasType(type)){
connection.addType(type);
}
let overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
// Arrow overlay needs to be cleared() (removed) if 'info_signature' gets removed!
// jsPlumb does not handle overlay updates for Arrow overlays... so we need to re-apply the the overlay manually
if(overlayArrow.path && !overlayArrow.path.isConnected){
connection.canvas.appendChild(overlayArrow.path);
}
let overlayType = 'Diamond'; // not specified
let arrowDirection = 1;
let arrowFoldback = 2;
if(connectionsData.hasOwnProperty(connectionId)){
// signature data found for current connection
signatureTypeData = MapUtil.getConnectionDataFromSignatures(connection, connectionsData[connectionId]);
let sourceLabel = signatureTypeData.source.labels;
let targetLabel = signatureTypeData.target.labels;
// add arrow (connection) overlay that points from "XXX" => "K162" ------------------------------------
if(
(sourceLabel.indexOf('K162') !== -1 && targetLabel.indexOf('K162') !== -1) ||
(sourceLabel.length === 0 && targetLabel.length === 0) ||
(
sourceLabel.length > 0 && targetLabel.length > 0 &&
sourceLabel.indexOf('K162') === -1 && targetLabel.indexOf('K162') === -1
)
){
// unknown direction
overlayType = 'Diamond'; // not specified
arrowDirection = 1;
arrowFoldback = 2;
}else if(
(sourceLabel.indexOf('K162') !== -1) ||
(sourceLabel.length === 0 && targetLabel.indexOf('K162') === -1)
){
// convert default arrow direction
overlayType = 'Arrow';
arrowDirection = -1;
arrowFoldback = 0.8;
}else{
// default arrow direction is fine
overlayType = 'Arrow';
arrowDirection = 1;
arrowFoldback = 0.8;
}
}
// class changes must be done on "connection" itself not on "overlayArrow"
// -> because Arrow might not be rendered to map at this point (if it does not exist already)
if(overlayType === 'Arrow'){
connection.updateClasses(
MapOverlayUtil.config.connectionArrowOverlaySuccessClass,
MapOverlayUtil.config.connectionArrowOverlayDangerClass
);
}else{
connection.updateClasses(
MapOverlayUtil.config.connectionArrowOverlayDangerClass,
MapOverlayUtil.config.connectionArrowOverlaySuccessClass
);
}
overlayArrow.updateFrom({
direction: arrowDirection,
foldback: arrowFoldback
});
// add endpoint overlays --------------------------------------------------------------------------
addEndpointOverlaySignatureLabel(sourceEndpoint, signatureTypeData.source);
addEndpointOverlaySignatureLabel(targetEndpoint, signatureTypeData.target);
}else{
// connection is not 'wh' scope
if(connection.hasType(type)){
connection.removeType(type);
}
}
});
});
};
/**
@@ -237,11 +248,10 @@ define([
/**
* git signature data that is linked to a connection for a mapId
* @param mapElement
* @param connections
* @param callback
*/
let getConnectionSignatureData = (mapElement, connections, callback) => {
let mapOverlay = $(mapElement).getMapOverlay('info');
let getConnectionSignatureData = (mapElement, callback) => {
let mapOverlay = MapOverlayUtil.getMapOverlay(mapElement, 'info');
let overlayConnectionIcon = mapOverlay.find('.pf-map-overlay-endpoint');
showLoading(overlayConnectionIcon);
@@ -259,46 +269,48 @@ define([
dataType: 'json',
context: {
mapElement: mapElement,
connections: connections,
overlayConnectionIcon: overlayConnectionIcon
}
}).done(function(connectionsData){
// hide all connection before add them (refresh)
this.mapElement.hideEndpointOverlays();
// ... add overlays
callback(this.connections, connectionsData);
let map = getMapObjectFromMapElement(this.mapElement);
callback(map, connectionsData);
}).always(function(){
hideLoading(this.overlayConnectionIcon);
});
};
/**
* showEndpointOverlays
* showInfoSignatureOverlays
* -> used by "refresh" overlays (hover) AND/OR initial menu trigger
*/
$.fn.showEndpointOverlays = function(){
$.fn.showInfoSignatureOverlays = function(){
let mapElement = $(this);
let map = getMapObjectFromMapElement(mapElement);
let MapUtil = require('app/map/util');
let connections = MapUtil.searchConnectionsByScopeAndType(map, 'wh', undefined, true);
// get connection signature information ---------------------------------------
getConnectionSignatureData(mapElement, connections, addConnectionsOverlay);
getConnectionSignatureData(mapElement, updateInfoSignatureOverlays);
};
/**
* hideEndpointOverlays
* -> see showEndpointOverlays()
* hideInfoSignatureOverlays
* -> see showInfoSignatureOverlays()
*/
$.fn.hideEndpointOverlays = function(){
$.fn.hideInfoSignatureOverlays = function(){
let map = getMapObjectFromMapElement($(this));
let MapUtil = require('app/map/util');
let connections = MapUtil.searchConnectionsByScopeAndType(map, 'wh');
let type = 'info_signature';
for(let connection of connections){
connection.removeOverlays(config.connectionOverlayArrowId);
connection.endpoints.forEach(removeEndpointOverlay);
}
map.batch(function(){
map.getAllConnections().forEach(function(connection){
let overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
if(overlayArrow){
overlayArrow.cleanup();
}
if(connection.hasType(type)){
connection.removeType(type, {}, true);
}
});
map.selectEndpoints().removeOverlay(MapOverlayUtil.config.endpointOverlayId);
});
};
/**
@@ -343,7 +355,7 @@ define([
hoverIntent: {
over: function(e){
let mapElement = Util.getMapElementFromOverlay(this);
mapElement.find('.' + config.systemHeadClass).each(function(){
mapElement.find('.' + MapOverlayUtil.config.systemHeadClass).each(function(){
let systemHead = $(this);
// init popover if not already exists
if(!systemHead.data('bs.popover')){
@@ -366,7 +378,7 @@ define([
},
out: function(e){
let mapElement = Util.getMapElementFromOverlay(this);
mapElement.find('.' + config.systemHeadClass).popover('hide');
mapElement.find('.' + MapOverlayUtil.config.systemHeadClass).popover('hide');
}
}
},
@@ -378,7 +390,7 @@ define([
hoverIntent: {
over: function(e){
let mapElement = Util.getMapElementFromOverlay(this);
mapElement.showEndpointOverlays();
mapElement.showInfoSignatureOverlays();
},
out: function(e){
// just "refresh" on hover
@@ -399,11 +411,10 @@ define([
hoverIntent: {
over: function(e){
let map = getMapObjectFromOverlayIcon(this);
let MapUtil = require('app/map/util');
let connections = MapUtil.searchConnectionsByScopeAndType(map, 'wh');
let serverDate = Util.getServerTime();
// show connection overlays ---------------------------------------------------
// show connection overlays -----------------------------------------------------------------------
for(let connection of connections){
let createdTimestamp = connection.getParameter('created');
let updatedTimestamp = connection.getParameter('updated');
@@ -420,13 +431,13 @@ define([
'<i class="fas fa-fw fa-pen-square"></i>&nbsp;' + formatTimeParts(updatedDiff)
];
// add label overlay ------------------------------------------------------
// add label overlay --------------------------------------------------------------------------
connection.addOverlay([
'Label',
{
label: labels.join('<br>'),
id: config.connectionOverlayWhId,
cssClass: [config.componentOverlayClass, 'small'].join(' '),
id: MapOverlayUtil.config.connectionOverlayWhId,
cssClass: [MapOverlayUtil.config.componentOverlayClass, 'small'].join(' '),
location: 0.35
}
]);
@@ -434,11 +445,10 @@ define([
},
out: function(e){
let map = getMapObjectFromOverlayIcon(this);
let MapUtil = require('app/map/util');
let connections = MapUtil.searchConnectionsByScopeAndType(map, 'wh');
for(let connection of connections){
connection.removeOverlays(config.connectionOverlayWhId);
connection.removeOverlay(MapOverlayUtil.config.connectionOverlayWhId);
}
}
}
@@ -451,7 +461,6 @@ define([
hoverIntent: {
over: function(e){
let map = getMapObjectFromOverlayIcon(this);
let MapUtil = require('app/map/util');
let connections = MapUtil.searchConnectionsByScopeAndType(map, 'wh', ['wh_eol']);
let serverDate = Util.getServerTime();
@@ -464,8 +473,8 @@ define([
'Label',
{
label: '<i class="far fa-fw fa-clock"></i>&nbsp;' + formatTimeParts(diff),
id: config.connectionOverlayEolId,
cssClass: [config.componentOverlayClass, 'eol'].join(' '),
id: MapOverlayUtil.config.connectionOverlayEolId,
cssClass: [MapOverlayUtil.config.componentOverlayClass, 'eol'].join(' '),
location: 0.25
}
]);
@@ -473,53 +482,26 @@ define([
},
out: function(e){
let map = getMapObjectFromOverlayIcon(this);
let MapUtil = require('app/map/util');
let connections = MapUtil.searchConnectionsByScopeAndType(map, 'wh', ['wh_eol']);
for(let connection of connections){
connection.removeOverlay(config.connectionOverlayEolId);
connection.removeOverlay(MapOverlayUtil.config.connectionOverlayEolId);
}
}
}
}
};
/**
* get map overlay element by type e.g. timer/counter, info - overlay
* @param overlayType
* @returns {*}
*/
$.fn.getMapOverlay = function(overlayType){
let mapWrapperElement = $(this).parents('.' + MapUtil.config.mapWrapperClass);
let mapOverlay = null;
switch(overlayType){
case 'timer':
mapOverlay = mapWrapperElement.find('.' + config.mapOverlayTimerClass);
break;
case 'info':
mapOverlay = mapWrapperElement.find('.' + config.mapOverlayInfoClass);
break;
case 'local':
mapOverlay = mapWrapperElement.find('.' + config.overlayLocalClass);
break;
}
return mapOverlay;
};
/**
* draws the map update counter to the map overlay timer
* @param mapOverlayTimer
* @param percent
* @param value
* @returns {*}
*/
$.fn.setMapUpdateCounter = function(percent, value){
let mapOverlayTimer = $(this);
let setMapUpdateCounter = (mapOverlayTimer, percent, value) => {
// check if counter already exists
let counterChart = mapOverlayTimer.getMapCounter();
let counterChart = MapOverlayUtil.getMapCounter(mapOverlayTimer);
if(counterChart.length === 0){
// create new counter
@@ -546,27 +528,14 @@ define([
return counterChart;
};
/**
* get the map counter chart from overlay
* @returns {JQuery|*|T|{}|jQuery}
*/
$.fn.getMapCounter = function(){
return $(this).find('.' + Init.classes.pieChart.pieChartMapCounterClass);
};
$.fn.getMapOverlayInterval = function(){
return $(this).getMapOverlay('timer').getMapCounter().data('interval');
};
/**
* start the map update counter or reset
*/
$.fn.startMapUpdateCounter = function(){
let mapOverlayTimer = $(this);
let counterChart = mapOverlayTimer.getMapCounter();
let counterChart = MapOverlayUtil.getMapCounter(mapOverlayTimer);
let maxSeconds = config.logTimerCount;
let maxSeconds = MapOverlayUtil.config.logTimerCount;
let counterChartLabel = counterChart.find('span');
@@ -709,6 +678,154 @@ define([
}
};
/**
* update map zoom overlay information
* @param map
*/
let updateZoomOverlay = map => {
let zoom = map.getZoom();
let zoomPercent = Math.round(zoom * 1000) / 10;
let zoomOverlay = MapOverlayUtil.getMapOverlay(map.getContainer(), 'zoom');
let zoomValue = zoomOverlay.find('.' + MapOverlayUtil.config.zoomOverlayValueClass);
let zoomUp = zoomOverlay.find('.' + MapOverlayUtil.config.zoomOverlayUpClass);
let zoomDown = zoomOverlay.find('.' + MapOverlayUtil.config.zoomOverlayDownClass);
zoomValue.toggleClass('active', zoom !== 1).text(zoomPercent);
zoomUp.toggleClass('disabled', zoom >= MapUtil.config.zoomMax);
zoomDown.toggleClass('disabled', zoom <= MapUtil.config.zoomMin);
};
/**
* map debug overlays for connections/endpoints
* -> requires manual added "debug" GET param to URL
* @param map
*/
let initMapDebugOverlays = map => {
let url = new URL(window.location.href);
if(url.searchParams.has('debug')){
let mapContainer = $(map.getContainer());
// debug map overlays for connection/endpoints
mapContainer.on('mouseover', '.jtk-connector', function(e){
e.stopPropagation();
if(e.target.classList.contains('jtk-connector-outline')){
let connection = e.currentTarget._jsPlumb;
// show debug overlay only if there is no active debug
if(!connection.getOverlay(MapOverlayUtil.config.debugOverlayId)){
// find nearby connections
let connections = [];
let endpoints = [];
let hasComponentId = id => {
return component => component.id === id;
};
for(let endpoint of connection.endpoints){
let connectionsInfo = map.anchorManager.getConnectionsFor(endpoint.elementId);
for(let connectionInfo of connectionsInfo){
if(!connections.some(hasComponentId(connectionInfo[0].id))){
connections.push(connectionInfo[0]);
for(let endpointTemp of connectionInfo[0].endpoints){
if(!endpoints.some(hasComponentId(endpointTemp.id))){
endpoints.push(endpointTemp);
}
}
}
}
}
let createConnectionOverlay = connection => {
let data = MapUtil.getDataByConnection(connection);
let html = '<div><table>';
html += '<tr><td>' + connection.id + '</td><td class="text-right">' + data.id + '</td></tr>';
html += '<tr><td>Scope:</td><td class="text-right">' + data.scope + '</td></tr>';
html += '<tr><td>Type:</td><td class="text-right">' + data.type.toString() + '</td></tr>';
html += '</table></div>';
return $(html).on('click', function(){
console.info(connection);
});
};
for(let connection of connections){
connection.addOverlay([
'Custom',
{
id: MapOverlayUtil.config.debugOverlayId,
cssClass: [MapOverlayUtil.config.componentOverlayClass, 'debug'].join(' '),
create: createConnectionOverlay
}
]);
}
let createEndpointOverlay = endpoint => {
let types = MapUtil.filterDefaultTypes(endpoint.getType());
let html = '<div><table>';
html += '<tr><td>' + endpoint.id + '</td><td class="text-right"></td></tr>';
html += '<tr><td>Scope:</td><td class="text-right">' + endpoint.scope + '</td></tr>';
html += '<tr><td>Type:</td><td class="text-right">' + types.toString() + '</td></tr>';
html += '</table></div>';
return $(html).on('click', function(){
console.info(endpoint);
});
};
for(let endpoint of endpoints){
endpoint.addOverlay([
'Custom',
{
id: MapOverlayUtil.config.debugOverlayId,
cssClass: [MapOverlayUtil.config.componentOverlayClass, 'debug'].join(' '),
create: createEndpointOverlay
}
]);
}
}
}
});
mapContainer.on('mouseover', function(e){
e.stopPropagation();
if(e.target === e.currentTarget){
map.select().removeOverlay(MapOverlayUtil.config.debugOverlayId);
map.selectEndpoints().removeOverlay(MapOverlayUtil.config.debugOverlayId);
}
});
}
};
/**
* init map zoom overlay
* @returns {jQuery}
*/
let initZoomOverlay = () => {
let clickHandler = e => {
let zoomIcon = $(e.target);
if(!zoomIcon.hasClass('disabled')){
let zoomAction = zoomIcon.attr('data-zoom');
let map = getMapObjectFromOverlayIcon(zoomIcon);
MapUtil.changeZoom(map, zoomAction);
}
};
return $('<div>', {
class: [MapOverlayUtil.config.mapOverlayClass, MapOverlayUtil.config.mapOverlayZoomClass].join(' ')
}).append(
$('<i>', {
class: ['fas', 'fa-caret-up', MapOverlayUtil.config.zoomOverlayUpClass].join(' ')
}).attr('data-zoom', 'up').on('click', clickHandler),
$('<span>', {
class: MapOverlayUtil.config.zoomOverlayValueClass,
text: '100'
}),
$('<i>', {
class: ['fas', 'fa-caret-down', MapOverlayUtil.config.zoomOverlayDownClass].join(' ')
}).attr('data-zoom', 'down').on('click', clickHandler)
);
};
/**
* init all map overlays on a "parent" element
* @returns {*}
@@ -718,14 +835,17 @@ define([
let parentElement = $(this);
let mapOverlayTimer = $('<div>', {
class: [config.mapOverlayClass, config.mapOverlayTimerClass].join(' ')
class: [MapOverlayUtil.config.mapOverlayClass, MapOverlayUtil.config.mapOverlayTimerClass].join(' ')
});
parentElement.append(mapOverlayTimer);
// ------------------------------------------------------------------------------------
parentElement.append(initZoomOverlay());
// --------------------------------------------------------------------------------------------------------
// add map overlay info. after scrollbar is initialized
let mapOverlayInfo = $('<div>', {
class: [config.mapOverlayClass, config.mapOverlayInfoClass].join(' ')
class: [MapOverlayUtil.config.mapOverlayClass, MapOverlayUtil.config.mapOverlayInfoClass].join(' ')
});
// add all overlay elements
@@ -758,12 +878,12 @@ define([
parentElement.append(mapOverlayInfo);
// reset map update timer
mapOverlayTimer.setMapUpdateCounter(100, config.logTimerCount);
setMapUpdateCounter(mapOverlayTimer, 100, MapOverlayUtil.config.logTimerCount);
});
};
return {
endpointOverlayId: config.endpointOverlayId
updateZoomOverlay: updateZoomOverlay,
initMapDebugOverlays: initMapDebugOverlays
};
});

View File

@@ -0,0 +1,97 @@
/**
* map overlay util functions
*/
define([
'jquery',
'app/init',
'app/util',
'app/map/util'
], ($, Init, Util) => {
'use strict';
let config = {
logTimerCount: 3, // map log timer in seconds
mapWrapperClass: 'pf-map-wrapper', // wrapper div (scrollable)
// map overlays sections
mapOverlayClass: 'pf-map-overlay', // class for all map overlays
mapOverlayTimerClass: 'pf-map-overlay-timer', // class for map overlay timer e.g. map timer
mapOverlayZoomClass: 'pf-map-overlay-zoom', // class for map overlay zoom
mapOverlayInfoClass: 'pf-map-overlay-info', // class for map overlay info e.g. map info
overlayLocalClass: 'pf-map-overlay-local', // class for map overlay "local" table
// system
systemHeadClass: 'pf-system-head', // class for system head
// connection overlay ids (they are not unique like CSS ids!)
connectionOverlayArrowId: 'pf-map-connection-arrow-overlay', // connection Arrows overlay ID (jsPlumb)
connectionOverlayWhId: 'pf-map-connection-wh-overlay', // connection WH overlay ID (jsPlumb)
connectionOverlayEolId: 'pf-map-connection-eol-overlay', // connection EOL overlay ID (jsPlumb)
debugOverlayId: 'pf-map-debug-overlay', // connection/endpoint overlay ID (jsPlumb)
endpointOverlayId: 'pf-map-endpoint-overlay', // endpoint overlay ID (jsPlumb)
// connection overlay classes classes
componentOverlayClass: 'pf-map-component-overlay', // class for "normal size" overlay
connectionArrowOverlaySuccessClass: 'pf-map-connection-arrow-overlay-success', // class for "success" arrow overlays
connectionArrowOverlayDangerClass: 'pf-map-connection-arrow-overlay-danger', // class for "danger" arrow overlays
// zoom overlay
zoomOverlayUpClass: 'pf-zoom-overlay-up',
zoomOverlayDownClass: 'pf-zoom-overlay-down',
zoomOverlayValueClass: 'pf-zoom-overlay-value'
};
/**
* get map overlay element by type e.g. timer/counter, info - overlay
* @param element
* @param overlayType
* @returns {null}
*/
let getMapOverlay = (element, overlayType) => {
let mapWrapperElement = $(element).parents('.' + config.mapWrapperClass);
let mapOverlay = null;
switch(overlayType){
case 'timer':
mapOverlay = mapWrapperElement.find('.' + config.mapOverlayTimerClass);
break;
case 'info':
mapOverlay = mapWrapperElement.find('.' + config.mapOverlayInfoClass);
break;
case 'zoom':
mapOverlay = mapWrapperElement.find('.' + config.mapOverlayZoomClass);
break;
case 'local':
mapOverlay = mapWrapperElement.find('.' + config.overlayLocalClass);
break;
}
return mapOverlay;
};
/**
* get the map counter chart from overlay
* @param element
* @returns {jQuery}
*/
let getMapCounter = element => $(element).find('.' + Init.classes.pieChart.pieChartMapCounterClass);
/**
* get interval value from map timer overlay
* @param element
* @returns {*}
*/
let getMapOverlayInterval = element => getMapCounter(getMapOverlay(element, 'timer')).data('interval');
return {
config: config,
getMapOverlay: getMapOverlay,
getMapCounter: getMapCounter,
getMapOverlayInterval: getMapOverlayInterval
};
});

View File

@@ -35,7 +35,7 @@ define([
advanced: {
updateOnContentResize: true,
autoExpandHorizontalScroll: true,
autoExpandHorizontalScroll: false, // on resize css scale() scroll content should not change
//autoExpandHorizontalScroll: 2,
autoScrollOnFocus: 'div',
},
@@ -72,25 +72,23 @@ define([
/**
* scroll to a specific position on map
* demo: http://manos.malihu.gr/repository/custom-scrollbar/demo/examples/scrollTo_demo.html
* @param scrollWrapper
* @param position
* @param options
*/
$.fn.scrollToPosition = function(position){
return this.each(function(){
$(this).mCustomScrollbar('scrollTo', position);
});
let scrollToPosition = (scrollWrapper, position, options) => {
$(scrollWrapper).mCustomScrollbar('scrollTo', position, options);
};
/**
* scroll to a specific system on map
* -> subtract some offset for tooltips/connections
* @param scrollWrapper
* @param position
* @returns {*}
*/
$.fn.scrollToSystem = function(position){
let scrollToSystem = (scrollWrapper, position) => {
position = getOffsetPosition(position, {x: -15, y: -35});
return this.each(function(){
$(this).mCustomScrollbar('scrollTo', position);
});
scrollToPosition(scrollWrapper, position);
};
/**
@@ -106,4 +104,9 @@ define([
y: Math.max(0, position.y + offset.y)
};
};
return {
scrollToPosition: scrollToPosition,
scrollToSystem: scrollToSystem
};
});

View File

@@ -5,13 +5,17 @@
define([
'jquery',
'app/init',
'app/util'
], ($, Init, Util) => {
'app/util',
'app/map/scrollbar',
'app/map/overlay/util'
], ($, Init, Util, Scrollbar, MapOverlayUtil) => {
'use strict';
let config = {
mapSnapToGridDimension: 20, // px for grid snapping (grid YxY)
defaultLocalJumpRadius: 3, // default search radius (in jumps) for "nearby" pilots
zoomMax: 1.5,
zoomMin: 0.5,
// local storage
characterLocalStoragePrefix: 'character_', // prefix for character data local storage key
@@ -53,8 +57,8 @@ define([
mapEndpoint : {
buttonId: Util.config.menuButtonEndpointId,
description: 'Endpoint overlay',
onEnable: 'showEndpointOverlays', // jQuery extension function
onDisable: 'hideEndpointOverlays' // jQuery extension function
onEnable: 'showInfoSignatureOverlays', // jQuery extension function
onDisable: 'hideInfoSignatureOverlays' // jQuery extension function
},
mapCompact : {
buttonId: Util.config.menuButtonCompactId,
@@ -312,7 +316,7 @@ define([
* @returns {*}
*/
let filterDefaultTypes = types => {
let defaultTypes = ['', 'default', 'state_active', 'state_process'];
let defaultTypes = ['', 'default', 'info_signature', 'state_active', 'state_process'];
return types.diff(defaultTypes);
};
@@ -434,7 +438,7 @@ define([
// remove connections from map
let removeConnections = connections => {
for(let connection of connections){
connection._jsPlumb.instance.detach(connection, {fireEvent: false});
connection._jsPlumb.instance.deleteConnection(connection, {fireEvent: false});
}
};
@@ -575,19 +579,15 @@ define([
*/
let getEndpointOverlaySignatureLocation = (endpoint, label) => {
let chars = label.length ? label.length : 2;
let xTop = chars === 2 ? +0.05 : chars <= 4 ? -0.75 : 3;
let xLeft = chars === 2 ? -1.10 : chars <= 4 ? -2.75 : 3;
let xRight = chars === 2 ? +1.25 : chars <= 4 ? +1.25 : 3;
let xBottom = chars === 2 ? +0.05 : chars <= 4 ? -0.75 : 3;
let xLeft = chars === 2 ? -0.5 : chars <= 4 ? -1 : 3;
let xRight = chars === 2 ? +1.5 : chars <= 4 ? +2.20 : 3;
let yTop = chars === 2 ? -1.10 : chars <= 4 ? -1.75 : 3;
switch(endpoint._continuousAnchorEdge){
case 'top': return [xTop, yTop];
case 'left': return [xLeft, 0];
case 'right': return [xRight, 0];
case 'bottom': return [xBottom , 1.3];
default: return [0.0, 0.0];
switch(endpoint.anchor.getCurrentFace()){
case 'top': return [0.5, -0.75];
case 'left': return [xLeft, 0.25];
case 'right': return [xRight, 0.25];
case 'bottom': return [0.5 , 1.75];
default: return [0.5, 0.5];
}
};
@@ -639,7 +639,6 @@ define([
*/
let filterMapByScopes = (map, scopes) => {
if(map){
// TODO ^^sometimes map is undefined -> bug
let mapElement = $(map.getContainer());
let allSystems = mapElement.getSystems();
let allConnections = map.getAllConnections();
@@ -684,7 +683,7 @@ define([
}
}
mapElement.getMapOverlay('info').updateOverlayIcon('filter', 'show');
MapOverlayUtil.getMapOverlay(mapElement, 'info').updateOverlayIcon('filter', 'show');
}else{
// clear filter
for(let system of allSystems){
@@ -694,11 +693,91 @@ define([
setConnectionVisible(connection, true);
}
mapElement.getMapOverlay('info').updateOverlayIcon('filter', 'hide');
MapOverlayUtil.getMapOverlay(mapElement, 'info').updateOverlayIcon('filter', 'hide');
}
}
};
/**
* in/de-crease zoom level
* @param map
* @param zoomAction
* @returns {boolean}
*/
let changeZoom = (map, zoomAction) => {
let zoomChange = false;
let zoom = map.getZoom();
let zoomStep = 0.1;
if('up' === zoomAction){
zoom += zoomStep;
}else{
zoom -= zoomStep;
}
zoom = Math.round(zoom * 10) / 10;
if(zoom >= config.zoomMin && zoom <= config.zoomMax){
zoomChange = setZoom(map, zoom);
}
return zoomChange;
};
/**
* set zoom level for a map
* @param map
* @param zoom
* @returns {boolean}
*/
let setZoom = (map, zoom = 1) => {
let zoomChange = false;
if(zoom !== map.getZoom()){
// zoom jsPlumb map http://jsplumb.github.io/jsplumb/zooming.html
let transformOrigin = [0, 0];
let el = map.getContainer();
let p = ['webkit', 'moz', 'ms', 'o'];
let s = 'scale(' + zoom + ')';
let oString = (transformOrigin[0] * 100) + '% ' + (transformOrigin[1] * 100) + '%';
for(let i = 0; i < p.length; i++){
el.style[p[i] + 'Transform'] = s;
el.style[p[i] + 'TransformOrigin'] = oString;
}
el.style.transform = s;
el.style.transformOrigin = oString;
zoomChange = map.setZoom(zoom);
// adjust mCustomScrollbar --------------------------------------------------------------------------------
let scaledWidth = el.getBoundingClientRect().width;
let scaledHeight = el.getBoundingClientRect().height;
let mapContainer = $(el);
let mapWidth = mapContainer.outerWidth(); // this is fix (should never change)
let mapHeight = mapContainer.outerHeight(); // this is fix (should never change)
let wrapperWidth = mapContainer.parents('.mCSB_container_wrapper').outerWidth(); // changes on browser resize (map window)
let wrapperHeight = mapContainer.parents('.mCSB_container_wrapper').outerHeight(); // changes on drag resize (map window)
let scrollableWidth = (zoom === 1 || mapWidth !== scaledWidth && scaledWidth > wrapperWidth);
let scrollableHeight = (zoom === 1 || mapHeight !== scaledHeight && scaledHeight > wrapperHeight);
mapContainer.parents('.mCSB_container').css({
'width': scrollableWidth ? scaledWidth + 'px' : (wrapperWidth - 50) + 'px',
'height': scrollableHeight ? scaledHeight + 'px' : (wrapperHeight) + 'px',
});
let mapWrapperElement = mapContainer.closest('.mCustomScrollbar');
if(scrollableWidth && scrollableHeight){
mapWrapperElement.mCustomScrollbar('update');
}else{
mapWrapperElement.mCustomScrollbar('scrollTo', '#pf-map-1', {
scrollInertia: 0,
scrollEasing: 'linear',
timeout: 0,
moveDragger: false
});
}
}
return zoomChange;
};
/**
* mark system as "selected" e.g. for dragging
* @param map
@@ -751,20 +830,96 @@ define([
system.toggleClass(config.systemHiddenClass, !visible);
};
/**
* add/remove connection type to connection that was previous registered by registerConnectionTypes()
* -> this method is a wrapper for addType()/removeType()
* with the addition of respecting active Arrow overlay direction
* @param action
* @param connection
* @param type
* @param params
* @param doNotRepaint
*/
let changeConnectionType = (action, connection, type, params = {}, doNotRepaint = false) => {
// check for active Arrow overlay
let overlayArrow, overlayArrowParams;
if(
type !== 'info_signature' &&
connection.hasType('info_signature')
){
overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
if(overlayArrow){
overlayArrowParams = {
direction: overlayArrow.direction,
foldback: overlayArrow.foldback,
};
}
}
// add the new type
connection[action](type, params, doNotRepaint);
// change Arrow overlay data back to initial direction
if(
overlayArrow &&
(
overlayArrow.direction !== overlayArrowParams.direction ||
overlayArrow.foldback !== overlayArrowParams.foldback
)
){
overlayArrow.updateFrom(overlayArrowParams);
if(!doNotRepaint){
connection.repaint();
}
}
};
/**
* add connection type to connection that was previous registered by registerConnectionTypes()
* @param connection
* @param type
* @param params
* @param doNotRepaint
*/
let addConnectionType = (connection, type, params = {}, doNotRepaint = false) => {
changeConnectionType('addType', connection, type, params, doNotRepaint);
};
/**
* remove connection type to connection that was previous registered by registerConnectionTypes()
* @param connection
* @param type
* @param params
* @param doNotRepaint
*/
let removeConnectionType = (connection, type, params = {}, doNotRepaint = false) => {
changeConnectionType('removeType', connection, type, params, doNotRepaint);
};
let toggleConnectionType = (connection, type, params = {}, doNotRepaint = false) => {
changeConnectionType('toggleType', connection, type, params, doNotRepaint);
};
/**
* mark a connection as "active"
* @param map
* @param connections
*/
let setConnectionsActive = (map, connections) => {
// set all inactive
for(let connection of getConnectionsByType(map, 'state_active')){
connection.removeType('state_active');
}
map.batch(() => {
// set all inactive
for(let connection of getConnectionsByType(map, 'state_active')){
if(!connections.includes(connection)){
removeConnectionType(connection, 'state_active');
}
}
for(let connection of connections){
connection.addType('state_active');
}
for(let connection of connections){
if(!connection.hasType('state_active')){
addConnectionType(connection, 'state_active');
}
}
});
};
/**
@@ -773,8 +928,11 @@ define([
* @param visible
*/
let setConnectionVisible = (connection, visible) => {
for(let endpoint of connection.endpoints){
endpoint.setVisible(visible);
if(connection.isVisible() !== visible){
connection.setVisible(visible, true);
for(let endpoint of connection.endpoints){
endpoint.setVisible(visible, true);
}
}
};
@@ -804,15 +962,18 @@ define([
let toggleConnectionActive = (map, connections) => {
let selectedConnections = [];
let deselectedConnections = [];
for(let connection of connections){
if(connection.hasType('state_active')){
connection.removeType('state_active');
deselectedConnections.push(connection);
}else{
connection.addType('state_active');
selectedConnections.push(connection);
map.batch(() => {
for(let connection of connections){
if(connection.hasType('state_active')){
removeConnectionType(connection, 'state_active');
deselectedConnections.push(connection);
}else{
addConnectionType(connection, 'state_active');
selectedConnections.push(connection);
}
}
}
});
updateConnectionInfo(map, selectedConnections, deselectedConnections);
};
@@ -1024,38 +1185,35 @@ define([
* @param {string} status
*/
let setConnectionWHStatus = (connection, status) => {
if(
status === 'wh_fresh' &&
connection.hasType('wh_fresh') !== true
){
connection.removeType('wh_reduced');
connection.removeType('wh_critical');
connection.addType('wh_fresh');
}else if(
status === 'wh_reduced' &&
connection.hasType('wh_reduced') !== true
){
connection.removeType('wh_fresh');
connection.removeType('wh_critical');
connection.addType('wh_reduced');
}else if(
status === 'wh_critical' &&
connection.hasType('wh_critical') !== true
){
connection.removeType('wh_fresh');
connection.removeType('wh_reduced');
connection.addType('wh_critical');
}else if(
status === 'wh_eol' &&
connection.hasType('wh_eol') !== true
){
connection.addType('wh_eol');
}else if(
status === 'wh_eol' &&
connection.hasType('wh_eol') !== true
){
connection.addType('wh_eol');
}
connection._jsPlumb.instance.batch(() => {
if(
status === 'wh_fresh' &&
connection.hasType('wh_fresh') !== true
){
removeConnectionType(connection, 'wh_reduced');
removeConnectionType(connection, 'wh_critical');
addConnectionType(connection, 'wh_fresh');
}else if(
status === 'wh_reduced' &&
connection.hasType('wh_reduced') !== true
){
removeConnectionType(connection, 'wh_fresh');
removeConnectionType(connection, 'wh_critical');
addConnectionType(connection, 'wh_reduced');
}else if(
status === 'wh_critical' &&
connection.hasType('wh_critical') !== true
){
removeConnectionType(connection, 'wh_fresh');
removeConnectionType(connection, 'wh_reduced');
addConnectionType(connection, 'wh_critical');
}else if(
status === 'wh_eol' &&
connection.hasType('wh_eol') !== true
){
addConnectionType(connection, 'wh_eol');
}
});
};
/**
@@ -1170,12 +1328,12 @@ define([
let visualizeMapExecutor = (resolve, reject) => {
// start map update counter -> prevent map updates during animations
mapElement.getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(mapElement, 'timer').startMapUpdateCounter();
let systemElements = mapElement.find('.' + config.systemClass);
let endpointElements = mapElement.find('.jsplumb-endpoint:visible');
let connectorElements = mapElement.find('.jsplumb-connector:visible');
let overlayElements = mapElement.find('.jsplumb-overlay:visible, .tooltip');
let endpointElements = mapElement.find('.jtk-endpoint:visible');
let connectorElements = mapElement.find('.jtk-connector:visible');
let overlayElements = mapElement.find('.jtk-overlay:visible, .tooltip');
let hideElements = (elements) => {
if(elements.length > 0){
@@ -1341,7 +1499,7 @@ define([
promiseStore.then(data => {
// This code runs once the value has been loaded from offline storage
if(data && data.scrollOffset){
mapWrapper.scrollToPosition([data.scrollOffset.y, data.scrollOffset.x]);
Scrollbar.scrollToPosition(mapWrapper, [data.scrollOffset.y, data.scrollOffset.x]);
}
resolve({
@@ -1404,7 +1562,7 @@ define([
if(rallyUpdated !== rally){
// rally status changed
if( !options.hideCounter ){
system.getMapOverlay('timer').startMapUpdateCounter();
MapOverlayUtil.getMapOverlay(system, 'timer').startMapUpdateCounter();
}
let rallyClass = getInfoForSystem('rally', 'class');
@@ -1812,11 +1970,13 @@ define([
markAsChanged: markAsChanged,
hasChanged: hasChanged,
toggleSystemsSelect: toggleSystemsSelect,
toggleConnectionType: toggleConnectionType,
toggleConnectionActive: toggleConnectionActive,
setSystemActive: setSystemActive,
showSystemInfo: showSystemInfo,
showConnectionInfo: showConnectionInfo,
showFindRouteDialog: showFindRouteDialog,
filterDefaultTypes: filterDefaultTypes,
getEndpointLabel: getEndpointLabel,
getConnectionsByType: getConnectionsByType,
getEndpointsDataByConnection: getEndpointsDataByConnection,
@@ -1837,6 +1997,8 @@ define([
getTabContentElementByMapElement: getTabContentElementByMapElement,
hasActiveConnection: hasActiveConnection,
filterMapByScopes: filterMapByScopes,
changeZoom: changeZoom,
setZoom: setZoom,
storeLocaleCharacterData: storeLocaleCharacterData,
getLocaleData: getLocaleData,
storeLocalData: storeLocalData,

View File

@@ -322,7 +322,7 @@ define([
}),
getMenuHeadline('Configuration'),
$('<a>', {
class: 'list-group-item',
class: ['list-group-item', 'loading'].join(' '),
html: '&nbsp;&nbsp;Settings'
}).prepend(
$('<i>',{
@@ -332,7 +332,7 @@ define([
$(document).triggerMenuEvent('ShowMapSettings', {tab: 'settings'});
}),
$('<a>', {
class: 'list-group-item',
class: ['list-group-item', 'loading'].join(' '),
id: Util.config.menuButtonGridId,
html:'&nbsp;&nbsp;Grid snapping'
}).prepend(
@@ -346,7 +346,7 @@ define([
});
}),
$('<a>', {
class: 'list-group-item',
class: ['list-group-item', 'loading'].join(' '),
id: Util.config.menuButtonMagnetizerId,
html: '&nbsp;&nbsp;Magnetizing'
}).prepend(
@@ -360,7 +360,7 @@ define([
});
}),
$('<a>', {
class: 'list-group-item',
class: ['list-group-item', 'loading'].join(' '),
id: Util.config.menuButtonEndpointId,
html: '&nbsp;&nbsp;Signatures'
}).prepend(
@@ -374,18 +374,13 @@ define([
});
}),
$('<a>', {
class: 'list-group-item',
class: ['list-group-item', 'loading'].join(' '),
id: Util.config.menuButtonCompactId,
html: '&nbsp;&nbsp;Compact'
}).prepend(
$('<i>',{
class: 'fas fa-compress fa-fw'
})
).append(
$('<span>',{
class: 'badge bg-color bg-color-gray txt-color txt-color-warning',
text: 'beta'
})
).on('click', function(){
Util.getMapModule().getActiveMap().triggerMenuEvent('MapOption', {
option: 'mapCompact',
@@ -743,6 +738,10 @@ define([
documentElement.on('pf:updateMenuOptions', function(e, data){
let hasRightMapDelete = MapUtil.checkRight('map_delete', data.mapConfig);
$('#' + Util.config.menuButtonMapDeleteId).toggleClass('disabled', !hasRightMapDelete);
// "loading" menu options require an active map
// -> active map now available -> remove loading class
$('.' + config.pageMenuRightClass + ' .loading').removeClass('loading');
});
// update header links with current map data
@@ -1311,5 +1310,4 @@ define([
initTabChangeObserver: initTabChangeObserver,
renderMapContextMenus: renderMapContextMenus
};
});

View File

@@ -62,23 +62,17 @@ define([
let disableOnScrollEvent = false;
// scroll breakpoints
let scrolLBreakpointElements = null;
let scrollBreakpointElements = $('.pf-manual-scroll-break');
// scroll navigation links
let scrollNavLiElements = null;
mapManualDialog.on('shown.bs.modal', function(e){
// modal on open
scrolLBreakpointElements = $('.pf-manual-scroll-break');
scrollNavLiElements = $('.' + config.dialogNavigationListItemClass);
});
let scrollNavLiElements = $('.' + config.dialogNavigationListItemClass);
let scrollspyElement = $('#' + config.mapManualScrollspyId);
let whileScrolling = function(){
if(disableOnScrollEvent === false){
for(let i = 0; i < scrolLBreakpointElements.length; i++){
let offset = $(scrolLBreakpointElements[i]).offset().top;
for(let i = 0; i < scrollBreakpointElements.length; i++){
let offset = $(scrollBreakpointElements[i]).offset().top;
if( (offset - modalOffsetTop) > 0){

View File

@@ -3056,6 +3056,18 @@ define([
*/
let isDomElement = obj => !!(obj && obj.nodeType === 1);
/**
* converts array of objects into object with properties
* @param array
* @param keyField
* @returns {*}
*/
let arrayToObject = (array, keyField = 'id') =>
array.reduce((obj, item) => {
obj[item[keyField]] = item;
return obj;
}, {});
/**
* get deep json object value if exists
* -> e.g. key = 'first.last.third' string
@@ -3262,6 +3274,7 @@ define([
htmlDecode: htmlDecode,
isValidHtml: isValidHtml,
isDomElement: isDomElement,
arrayToObject: arrayToObject,
getObjVal: getObjVal,
redirect: redirect,
logout: logout,

File diff suppressed because it is too large Load Diff

View File

@@ -77,13 +77,14 @@ $.fn.dragToSelect = function (conf) {
// deselected items
var deselectedItems = $();
/*
do {
if (/auto|scroll|hidden/.test(parent.css('overflow'))) {
break;
}
parent = parent.parent();
} while (parent[0].parentNode);
*/
// Does user want to disable dragToSelect
if (conf == 'disable') {
parent.addClass(config.disabledClass);
@@ -133,8 +134,8 @@ $.fn.dragToSelect = function (conf) {
return;
}
selectBoxOrigin.left = e.pageX - parentDim.left + parent[0].scrollLeft - 5;
selectBoxOrigin.top = e.pageY - parentDim.top + parent[0].scrollTop - 5;
selectBoxOrigin.left = e.pageX - parentDim.left + parent[0].scrollLeft;
selectBoxOrigin.top = e.pageY - parentDim.top + parent[0].scrollTop;
var css = {
left: selectBoxOrigin.left + 'px',
@@ -342,7 +343,7 @@ $.fn.dragToSelect = function (conf) {
}
var mouseupCallback = function(){
if (config.selectables){
if(config.selectables){
selectElementsInRange();
}
hideSelectBox();
@@ -364,10 +365,10 @@ $.fn.dragToSelect = function (conf) {
}).mouseup(mouseupCallback);
parent.mousedown(function(e){
if (
if(
e.which === 1 && // left mouse down
e.target === realParent[0] // prevent while dragging a system :)
) {
){
// Make sure user isn't clicking scrollbar (or disallow clicks far to the right actually)
if ((e.pageX + 20) > $(document.body).width()) {
return;
@@ -386,7 +387,6 @@ $.fn.dragToSelect = function (conf) {
e.preventDefault();
}).mouseup(mouseupCallback);
// Be nice
return this;
};

View File

@@ -3,7 +3,7 @@
<div class="col-sm-6">
<h4>{{label}}</h4>
<table class="table table-condensed">
<table class="table table-condensed" style="font-size: 12px">
<tbody>
{{#events}}
<tr>

View File

@@ -34,6 +34,21 @@
top:0px;
}
};
// svg path draw ==================================================================================
.pf-animation-path-draw {
stroke-dasharray: 500;
stroke-dashoffset: 500;
animation: pfPathDraw 3s linear alternate infinite;
}
@include keyframes(pfPathDraw){
from {
stroke-dashoffset: 500;
}
to {
stroke-dashoffset: 0;
}
}
// bubble =========================================================================================
@include keyframes(pfBubbleWobble){

View File

@@ -692,6 +692,19 @@ table{
right: 8px;
}
}
&.loading{
pointer-events: none;
color: $navbar-default-link-color;
&:after{
content: '\f021';
font-family: 'Font Awesome 5 Free';
font-weight: bold;
position: absolute;
right: 8px;
animation: fa-spin 2s infinite linear;
}
}
}
// custom scrollbars ==============================================================================
@@ -699,6 +712,11 @@ table{
will-change: top, left;
}
.mCSB_container{
overflow-x: visible !important; // for map zoom
overflow-y: visible !important; // for map zoom
}
// log types ======================================================================================
.pf-log-info{
@extend .txt-color-green;

View File

@@ -6,6 +6,11 @@ $mapWrapperMinHeight: 250px;
$mapWrapperMaxHeight: 1000px; // no vertical scrollbar: $mapHeight + 35px;
$mapWrapperMaxWidth: $mapWidth + 35px;
$mapOverlayTop: 8px;
$mapOverlayRight: 25px;
$mapOverlayBottom: 25px;
$mapOverlayLeft: 5px;
$mapBubbleWidth: 30px;
// start bounce mixin =================================================================================================
@@ -30,6 +35,10 @@ $mapBubbleWidth: 30px;
margin: 0 auto;
}
.pf-map-move{
cursor: move !important;
}
.pf-map-tab-content{
.pf-map-wrapper{
@@ -78,18 +87,61 @@ $mapBubbleWidth: 30px;
position: absolute;
display: none; // triggered by js
z-index: 10000;
right: 25px;
background: rgba($black, 0.25);
@include border-radius(5px);
&.pf-map-overlay-timer{
bottom: 23px;
right: $mapOverlayRight;
bottom: $mapOverlayBottom;
width: 36px;
height: 36px;
height: 38px;
}
&.pf-map-overlay-zoom{
bottom: $mapOverlayBottom;
left: $mapOverlayLeft;
width: 26px;
height: 52px;
padding: 2px 4px;
display: block;
.pf-zoom-overlay-up,
.pf-zoom-overlay-down{
display: block;
text-align: center;
font-size: 16px;
cursor: pointer;
@include transition(color .18s ease-in-out);
will-change: color;
&:hover{
color: $orange-dark;
}
&.disabled{
cursor: not-allowed;
color: $gray-darker;
}
}
.pf-zoom-overlay-value{
display: block;
margin-top: 2px;
text-align: center;
font-size: 11px;
line-height: 13px;
@include transition(color .18s ease-in-out);
will-change: color;
}
.active{
color: $orange-dark;
}
}
&.pf-map-overlay-info{
top: 8px;
top: $mapOverlayTop;
right: $mapOverlayRight;
height: 36px;
min-height: 36px;
min-width: 36px;
@@ -105,7 +157,7 @@ $mapBubbleWidth: 30px;
color: $gray-light;
transform: scale(0);
transform-origin: 50% 50% 0px;
@include transition( color .18s ease-in-out );
@include transition(color .18s ease-in-out );
cursor: help;
will-change: all;
@@ -127,6 +179,7 @@ $mapBubbleWidth: 30px;
&.pf-map-overlay-local{
top: 54px;
right: $mapOverlayRight;
min-height: 80px;
width: 32px;
display: block;
@@ -235,35 +288,18 @@ $mapBubbleWidth: 30px;
height: $mapHeight;
position: relative;
font-family: $font-family-bold;
will-change: transform;
// jsPlumb classes ==================================================================================================
.jsplumb-overlay{
opacity: 1;
pointer-events: none; // click through overlays
will-change: opacity;
@include transition( opacity 0.18s ease-out);
}
// system that is currently dragged
.jsPlumb_dragged{
.jtk-drag{
@extend .pf-system-selected;
}
// hover effects ====================================================================================================
.jsplumb-hover{
// hover effect for connections
&.jsplumb-overlay{
opacity: 0 !important; // hide opacity on hover
}
&:not(.jsplumb-overlay){
@include bounce-up-down; // label should not bounce
}
.jtk-hover:not(.jtk-overlay){
@include bounce-up-down; // label should not bounce
}
// hover effect for systems
.jsplumb-target-hover, .jsplumb-source-hover{
.jtk-source-hover, .jtk-target-hover{
@include bounce-up-down;
@include box-shadow(0 6px 12px rgba(0,0,0,.3));
}
@@ -277,7 +313,7 @@ $mapBubbleWidth: 30px;
background-color: $gray-dark;
font-family: $font-family-bold;
z-index: 100;
will-change: top, left, opacity;
will-change: top, left, opacity, transform;
//opacity: 0; // trigger by js
border: {
@@ -294,11 +330,7 @@ $mapBubbleWidth: 30px;
&:hover{
// makes the systems "flying" :)
@include box-shadow(0 6px 12px rgba(0,0,0, 0.3));
@include transform( translate3d(0, -1px, 0) !important);
&:not(.jsPlumb_dragged){
z-index: 1040 !important; // should overlap connection endpoint overlays,not for dragged elements -> prevent "show/hide flickering" of overlays
}
@include transform(translate3d(0, -1px, 0) !important);
}
.pf-system-head{
@@ -412,6 +444,7 @@ $mapBubbleWidth: 30px;
text-overflow: ellipsis;
display: none; // hover effect
}
// user status ================================================================================================
.pf-user-status{
font-size: 6px;
@@ -491,24 +524,21 @@ $mapBubbleWidth: 30px;
}
// Endpoints ========================================================================================================
.pf-map-endpoint-source, .pf-map-endpoint-target{
.jtk-endpoint{
z-index: 90;
svg {
overflow: visible; // this fixes a "half-pixel" bug on SVG circle with border
circle{
@include transition(stroke 0.18s ease-out, fill 0.18s ease-out);
}
*{
stroke: $gray-light;
stroke-width: 2; // border width
fill: $gray;
cursor: pointer;
}
}
// hover (with cursor) effect for Endpoints
// hover (with cursor) on endpoints (before drag)
&:hover{
circle{
stroke: $orange !important;
@@ -516,9 +546,8 @@ $mapBubbleWidth: 30px;
}
// hover class (e.g. connection is hovered -> endpoints get this class)
&.jsplumb-hover{
// increase z-index -> prevent overlapping multiple endpoints
z-index: 95;
&.jtk-hover{
z-index: 95; // increase z-index -> prevent overlapping multiple endpoints
&.pf-map-endpoint-bubble{
&:after{
@@ -529,36 +558,13 @@ $mapBubbleWidth: 30px;
}
}
// while dragging
&.jsplumb-dragging{
circle {
stroke: $orange;
}
}
}
.jsplumb-endpoint-drop-allowed{
circle {
stroke: $green !important;
fill: $green !important;
}
}
.jsplumb-endpoint-drop-forbidden{
circle {
stroke: $red-darker !important;
fill: $red-darker !important;
}
}
.jsplumb-endpoint{
&:after{
content: url("#{$base-url}/bubble.svg");
position: absolute;
display: block;
pointer-events: none;
top: ($mapBubbleWidth / -2) + 5;
left: ($mapBubbleWidth / -2) + 5;
top: ($mapBubbleWidth / -2) + 7;
left: ($mapBubbleWidth / -2) + 7;
width: $mapBubbleWidth;
height: $mapBubbleWidth;
z-index: -1;
@@ -583,12 +589,24 @@ $mapBubbleWidth: 30px;
}
}
// Connections ======================================================================================================
.jtk-endpoint-drop-allowed{
circle {
stroke: $green !important;
fill: $green !important;
}
}
svg.jsplumb-connector{
.jtk-endpoint-drop-forbidden{
circle {
stroke: $red-darker !important;
fill: $red-darker !important;
}
}
// Connections ======================================================================================================
.jtk-connector{
z-index: 40; // min z-index for connections
cursor: pointer;
opacity: 1; // for animation
stroke-linecap: round; // line endings
@include transition(stroke 0.18s ease-out, opacity 0.18s ease-out);
will-change: all;
@@ -596,37 +614,22 @@ $mapBubbleWidth: 30px;
@include transition(stroke 0.18s ease-out);
}
path:nth-child(2){
stroke: $gray; // inner line
}
&.jtk-hover{
z-index: 80; // max z-index for connections
filter: drop-shadow(-3px 3px 4px rgba(0,0,0, 0.3));
path:first-child{
stroke: $gray-light; // outer line
}
&.jsplumb-hover{
z-index: 80;
filter: drop-shadow( -3px 3px 4px rgba(0,0,0, 0.3));
&:not(.pf-map-connection-jumpbridge):not(.pf-map-connection-abyssal) path:first-child{
stroke: $gray-lightest; // hover style (outer SVG)
}
&.pf-map-connection-jumpbridge, &.pf-map-connection-abyssal{
path:nth-child(2){
stroke: $gray-lightest; // hover style (inner SVG)
}
path:first-child{
stroke: $gray-lightest;
}
}
&.jsplumb-dragging{
@include transition( opacity 0.18s ease-out) ;
&.jtk-dragging{
z-index: 80; // max z-index for connections
opacity: 0.4;
z-index: 80;
}
}
svg.pf-map-connection-abyssal {
.pf-map-connection-abyssal {
z-index: 40;
path:first-child{
@@ -637,7 +640,7 @@ $mapBubbleWidth: 30px;
stroke: darken($pink-darker, 8%);
}
&:hover{
&.jtk-hover{
path:first-child{
stroke: rgba(255,255,255,0); // invisible border color
}
@@ -648,7 +651,7 @@ $mapBubbleWidth: 30px;
}
}
svg.pf-map-connection-jumpbridge {
.pf-map-connection-jumpbridge {
z-index: 50;
path:first-child{
@@ -659,7 +662,7 @@ $mapBubbleWidth: 30px;
stroke: $teal-lighter;
}
&:hover{
&.jtk-hover{
path:first-child{
stroke: rgba(255,255,255,0); // invisible border color
}
@@ -670,7 +673,7 @@ $mapBubbleWidth: 30px;
}
}
svg.pf-map-connection-stargate {
.pf-map-connection-stargate {
z-index: 60;
path:first-child{
@@ -680,55 +683,48 @@ $mapBubbleWidth: 30px;
path:nth-child(2){
stroke: $indigo-darkest;
}
&:hover{
path:first-child{
stroke: $gray-lightest;
}
}
}
svg{
&.pf-map-connection-wh-fresh,
&.pf-map-connection-wh-reduced,
&.pf-map-connection-wh-critical,
&.pf-map-connection-wh-eol{
z-index: 70;
}
.pf-map-connection-wh-fresh,
.pf-map-connection-wh-reduced,
.pf-map-connection-wh-critical,
.pf-map-connection-wh-eol{
z-index: 70;
}
svg.pf-map-connection-wh-eol {
.pf-map-connection-wh-eol {
path:first-child{
stroke: $pink-dark;
}
&:hover{
path:first-child{
stroke: $gray-lightest;
}
}
}
svg.pf-map-connection-wh-reduced {
.pf-map-connection-wh-reduced {
path:nth-child(2){
stroke: $orange;
}
}
svg.pf-map-connection-wh-critical {
.pf-map-connection-wh-critical {
path:nth-child(2){
stroke: $red-darker;
}
}
svg.pf-map-connection-active{
filter: drop-shadow( 0px 0px 3px $yellow-lighter);
.pf-map-connection-frig{
path:nth-child(2){
stroke-linecap: square !important;
}
}
svg.pf-map-connection-process{
.pf-map-connection-active{
filter: drop-shadow( 0px 0px 3px $yellow-lighter) !important; // overwrite "hover" shadow
}
.pf-map-connection-process{
opacity: 0.4 !important;
path{
@@ -737,6 +733,17 @@ $mapBubbleWidth: 30px;
}
// Overlays =========================================================================================================
.jtk-overlay{
opacity: 1;
pointer-events: none; // click through overlays
will-change: opacity;
@include transition(opacity 0.18s ease-out);
&.jtk-hover:not(.debug){
opacity: 0 !important;
}
}
%map-overlay{
font-size: 10px;
z-index: 1020;
@@ -746,6 +753,7 @@ $mapBubbleWidth: 30px;
.pf-map-component-overlay{
@extend %map-overlay;
line-height: 14px;
padding: 1px 4px;
@include border-radius(6px);
@include box-shadow(0 6px 12px rgba(0,0,0,.4));
@@ -760,11 +768,21 @@ $mapBubbleWidth: 30px;
}
&.icon{
line-height: 10px;
font-size: 12px;
line-height: 12px;
padding: 0;
@include border-radius(5px);
width: 12px;
height: 12px;
overflow: hidden;
text-align: center;
@include border-radius(50%);
@include box-shadow(0 3px 6px rgba(0,0,0,.3));
}
&.debug{
background-color: $purple-dark;
opacity: 0.8;
}
}
// Connection overlays ==============================================================================================
@@ -772,10 +790,7 @@ $mapBubbleWidth: 30px;
@extend %map-overlay;
background-color: transparent;
//margin-top: -14px;
font-size: 12px;
margin-left: -7px;
margin-top: -7px;
width: 15px;
height: 15px;
opacity: 0.4 !important;
@@ -798,18 +813,22 @@ $mapBubbleWidth: 30px;
}
// Arrow overlays ===================================================================================================
.pf-map-connection-arrow-overlay{
stroke: $gray-dark;
fill: $green;
.pf-map-connection-arrow-overlay-success{
.pf-map-connection-arrow-overlay{
stroke: $gray-dark;
fill: $green;
}
}
.pf-map-connection-diamond-overlay{
stroke: $gray-dark;
fill: $red;
.pf-map-connection-arrow-overlay-danger{
.pf-map-connection-arrow-overlay{
stroke: $gray-dark;
fill: $red;
animation-name: pfPulseDanger;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-name: pfPulseDanger;
animation-duration: 4s;
animation-iteration-count: infinite;
}
}
}

View File

@@ -0,0 +1,602 @@
/*
Default styles for jsPlumb Toolkit
Copyright 2018 https://jsplumbtoolkit.com
*/
/* --------------------------------------------------------------------------------------------- */
/* --- SURFACE WIDGET -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------------------------- */
/*
Assigned to every Node managed by an instance of the Toolkit. They are required to be positioned absolute, to
enable dragging to work properly.
*/
.jtk-node {
position: absolute;
}
/*
Assigned to every Group managed by an instance of the Toolkit. They are required to be positioned absolute, to
enable dragging to work properly. We set overflow:visible on Group elements too, as a drag outside of the bounds
is automatically reverted anyway, and without overflow:visible you cannot drag a node to some other element. You can
also drag a node out of the element's viewport and if you drop it you can never get it back.
*/
.jtk-group {
position: absolute;
overflow: visible;
}
/*
This is the attribute used to mark which part of a Group DOM element should contain the child Nodes. We mark it
as having `position:relative` so that the absolute positioned Nodes are drawn correctly.
*/
[jtk-group-content] {
position:relative;
}
/*
This style was created in response to this Chrome bug:
http://stackoverflow.com/questions/13758215/artifacts-when-css-scaled-in-chrome
Basically it's about how sometimes there can be artefacts left on screen when the user drags an element. It seems
the issue has been fixed in more recent versions of Chrome, but the style is left here in case you come across
the problem.
*/
.jtk-node.jtk-drag {
/*-webkit-backface-visibility: hidden;*/
}
/*
Suppresses the pointer events on an element that was created by Katavorio in response to a drag in which the element
should first be cloned. Having this clone ignore pointer events means there is less chance that any other
mouse activity (such as click) on the original element will not be consumed by katavorio.
*/
.katavorio-clone-drag {
pointer-events:none;
}
/*
Assigned to an element that is the `Container` in a `render` call.
Elements that are acting as Surface widgets should have overflow:hidden set to prevent libs from
scrolling them during drag (we don't want scrollbars; we have an infinite canvas). Position is set to
`relative` as this is the parent for nodes, which are positioned absolute (and for absolute positioning
to work, you need to ensure the parent node has `position:relative`). This style also sets some default
values for the cursor - using a `grab` cursor where supported.
*/
.jtk-surface {
overflow: hidden !important;
position: relative;
cursor: move;
cursor: -moz-grab;
cursor: -webkit-grab;
/*
For IE10+. As discussed on this page:
https://msdn.microsoft.com/en-us/library/ie/jj583807(v=vs.85).aspx
Microsoft have very helpfully implemented default behaviours for a bunch of touch events and
then consumed the events so you don't have to be bothered by them. They've "done a lot of research"
about this stuff and put together a really great default experience for everyone in the entire world.
*/
touch-action:none;
/*
Another Chrome issue that appears to have been fixed in later versions
http://stackoverflow.com/questions/15464055/css-transition-effect-makes-image-blurry-moves-image-1px-in-chrome
*/
/*
-webkit-backface-visibility: hidden;
-webkit-transform: translateZ(0) scale(1.0, 1.0);
*/
}
/*
Assigned to the surface when it is being panned. The default is to change the cursor (in browsers that support
a `grabbing` cursor), and to disable text selection.
*/
.jtk-surface-panning {
cursor: -moz-grabbing;
cursor: -webkit-grabbing;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/*
The work area in a surface renderer.
*/
.jtk-surface-canvas {
overflow: visible !important;
}
/*
For IE10+. Discussed above in the .jtk-surface styles. This one is specific to elements that are configured
to be droppable on a Surface via its `registerDroppableNodes` method.
*/
.jtk-surface-droppable-node {
touch-action:none;
}
/*
Assigned to a Surface widget when panning is disabled (and therefore the app is relying on scrollbars when the content overflows).
*/
.jtk-surface-nopan {
overflow: scroll !important;
cursor:default;
}
/*
Assigned to tile images in a tiled background
*/
.jtk-surface-tile {
border:none;
outline:none;
margin:0;
-webkit-transition: opacity .3s ease .15s;
-moz-transition: opacity .3s ease .15s;
-o-transition: opacity .3s ease .15s;
-ms-transition: opacity .3s ease .15s;
transition: opacity .3s ease .15s;
}
/*
Assigned to the element used for node select with the mouse ("lasso").
*/
.jtk-lasso {
border: 2px solid rgb(49, 119, 184);
background-color: WhiteSmoke;
opacity: 0.5;
display: none;
z-index: 20000;
position: absolute;
}
/*
This class is added to the document body on lasso drag start and removed at the end of lasso dragging. Its purpose
is to switch off text selection on all elements while the user is dragging the lasso.
*/
.jtk-lasso-select-defeat * {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/**
Added to the lasso mask when it is operating in 'inverted' mode, ie. the excluded parts of the UI are covered, rather
than the normal mode in which the selected parts of the UI are covered.
*/
.jtk-lasso-mask {
position:fixed;
z-index:20000;
display:none;
opacity:0.5;
background-color: #07234E;
top:0;
bottom:0;
left:0;
right:0;
}
/*
Assigned to some element that has been selected (either via lasso or programmatically).
*/
.jtk-surface-selected-element {
border: 2px dashed #f76258 !important;
}
/*
Assigned to all pan buttons in a surface widget.
*/
.jtk-surface-pan {
background-color: Azure;
opacity: 0.4;
text-align: center;
cursor: pointer;
z-index: 2;
-webkit-transition: background-color 0.15s ease-in;
-moz-transition: background-color 0.15s ease-in;
-o-transition: background-color 0.15s ease-in;
transition: background-color 0.15s ease-in;
}
/*
Specific styles for the top and bottom pan buttons.
Top/bottom are 100% width and 20px high by default
*/
.jtk-surface-pan-top, .jtk-surface-pan-bottom {
width: 100%;
height: 20px;
}
/*
Hover styles for all pan buttons.
On hover, change color, background color, font weight and opacity.
*/
.jtk-surface-pan-top:hover, .jtk-surface-pan-bottom:hover, .jtk-surface-pan-left:hover, .jtk-surface-pan-right:hover {
opacity: 0.6;
background-color: rgb(49, 119, 184);
color: white;
font-weight: bold;
}
/*
Specific styles for the left and right pan buttons.
Left/right pan buttons are 100% height and 20px wide
*/
.jtk-surface-pan-left, .jtk-surface-pan-right {
width: 20px;
height: 100%;
line-height: 40;
}
/*
Assigned to a pan button when the user is pressing it.
*/
.jtk-surface-pan-active, .jtk-surface-pan-active:hover {
background-color: #f76258;
}
/* --------------------------------------------------------------------------------------------- */
/* --- MINIVIEW WIDGET ------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------------------------- */
/*
Assigned to an element that is acting as a Miniview.
As with Surface, Miniview elements should have overflow:hidden set to prevent
libs from scrolling them during drag. This style also provides a default width/height for a miniview,
which you may wish to override.
*/
.jtk-miniview {
overflow: hidden !important;
width: 125px;
height: 125px;
position: relative;
background-color: #B2C9CD;
border: 1px solid #E2E6CD;
border-radius: 4px;
opacity: 0.8;
}
/*
Assigned to the element that shows the size of the related viewport in a Miniview widget, and which can be dragged to
move the surface.
*/
.jtk-miniview-panner {
border: 5px dotted WhiteSmoke;
opacity: 0.4;
background-color: rgb(79, 111, 126);
cursor: move;
cursor: -moz-grab;
cursor: -webkit-grab;
}
/*
Assigned to the miniview's panner when it is being dragged.
*/
.jtk-miniview-panning {
cursor: -moz-grabbing;
cursor: -webkit-grabbing;
}
/*
Added to all elements displayed in a miniview.
*/
.jtk-miniview-element {
background-color: rgb(96, 122, 134);
position: absolute;
}
/*
Added to Group elements displayed in a miniview
*/
.jtk-miniview-group-element {
background: transparent;
border: 2px solid rgb(96,122,134);
}
/*
Assigned to the collapse/expand miniview button
*/
.jtk-miniview-collapse {
color: whiteSmoke;
position: absolute;
font-size: 18px;
top: -1px;
right: 3px;
cursor: pointer;
font-weight: bold;
}
/*
The '-' symbol when the miniview is expanded
*/
.jtk-miniview-collapse:before {
content: "\2012";
}
/*
Assigned to the miniview element when it is collapsed.
*/
.jtk-miniview-collapsed {
background-color: #449ea6;
border-radius: 4px;
height: 22px;
margin-right: 0;
padding: 4px;
width: 21px;
}
/*
Hide all children of the miniview (except the expand button) when it is collapsed so you don't see anything
poking through under the + icon.
*/
.jtk-miniview-collapsed .jtk-miniview-element, .jtk-miniview-collapsed .jtk-miniview-panner {
visibility: hidden;
}
/*
The '+' symbol when the miniview is collapsed.
*/
.jtk-miniview-collapsed .jtk-miniview-collapse:before {
content: "+";
}
/*
Hover state for the collapse/expand icon.
*/
.jtk-miniview-collapse:hover {
color: #E4F013;
}
/* ------------------------------------------------------------------------------------------- */
/* --- DIALOGS --------------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------------------------- */
/*
This is the element that acts as the dialog underlay - the modal "mask". Note the high z-index default
set here (and note also the overlay style below has a z-index with a value higher by one).
*/
.jtk-dialog-underlay {
left: 0;
right: 0;
top: 0;
bottom: 0;
position: fixed;
z-index: 100000;
opacity: 0.8;
background-color: #CCC;
display: none;
}
/*
This is the element that acts as the parent for dialog content.
*/
.jtk-dialog-overlay {
position: fixed;
z-index: 100001;
display: none;
background-color: white;
font-family: "Open Sans", sans-serif;
padding: 7px;
box-shadow: 0 0 5px gray;
overflow: hidden;
}
.jtk-dialog-overlay-x {
max-height:0;
transition: max-height 0.5s ease-in;
-moz-transition: max-height 0.5s ease-in;
-ms-transition: max-height 0.5s ease-in;
-o-transition: max-height 0.5s ease-in;
-webkit-transition: max-height 0.5s ease-in;
}
.jtk-dialog-overlay-y {
max-width:0;
transition: max-width 0.5s ease-in;
-moz-transition: max-width 0.5s ease-in;
-ms-transition: max-width 0.5s ease-in;
-o-transition: max-width 0.5s ease-in;
-webkit-transition: max-width 0.5s ease-in;
}
.jtk-dialog-overlay-top {
top:20px;
}
.jtk-dialog-overlay-bottom {
bottom:20px;
}
.jtk-dialog-overlay-left {
left:20px;
}
.jtk-dialog-overlay-right {
right:20px;
}
.jtk-dialog-overlay-x.jtk-dialog-overlay-visible {
max-height:1000px;
}
.jtk-dialog-overlay-y.jtk-dialog-overlay-visible {
max-width:1000px;
}
/*
The element containing buttons in a dialog.
*/
.jtk-dialog-buttons {
text-align: right;
margin-top: 5px;
}
/*
An individual button in a dialog.
*/
.jtk-dialog-button {
border: none;
cursor: pointer;
margin-right: 5px;
min-width: 56px;
background-color: white;
outline: 1px solid #ccc;
}
/*
Hover style for an individual button in a dialog.
*/
.jtk-dialog-button:hover {
color: white;
background-color: #234b5e;
}
/*
The titlebar of a dialog.
*/
.jtk-dialog-title {
text-align: left;
font-size: 14px;
margin-bottom: 9px;
}
.jtk-dialog-content {
font-size:12px;
text-align:left;
min-width:250px;
margin: 0 14px;
}
.jtk-dialog-content ul {
width:100%;
padding-left:0;
}
.jtk-dialog-content label {
cursor: pointer;
font-weight: inherit;
}
.jtk-dialog-overlay input, .jtk-dialog-overlay textarea {
background-color: #FFF;
border: 1px solid #CCC;
color: #333;
font-size: 14px;
font-style: normal;
outline: none;
padding: 6px 4px;
margin-right: 6px;
}
.jtk-dialog-overlay input:focus, .jtk-dialog-overlay textarea:focus {
background-color: #cbeae1;
border: 1px solid #83b8a8;
color: #333;
font-size: 14px;
font-style: normal;
outline: none;
}
/* -------------------------------------------------------------------------------------------- */
/* --- DRAWING TOOLS -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------------------------- */
/*
Assigned to the element that is drawn around some other element when a drawing operation is taking place.
*/
.jtk-draw-skeleton {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
outline: 2px solid #84acb3;
opacity: 0.8;
}
/*
Assigned to every handle (top left, top right, bottom left, bottom right, center) in a draw skeleton.
*/
.jtk-draw-handle {
position: absolute;
width: 7px;
height: 7px;
background-color: #84acb3;
}
/*
Assigned to the top left handle in a draw skeleton
*/
.jtk-draw-handle-tl {
left: 0;
top: 0;
cursor: nw-resize;
}
/*
Assigned to the top right handle in a draw skeleton
*/
.jtk-draw-handle-tr {
right: 0;
top: 0;
cursor: ne-resize;
}
/*
Assigned to the bottom left handle in a draw skeleton
*/
.jtk-draw-handle-bl {
left: 0;
bottom: 0;
cursor: sw-resize;
}
/*
Assigned to the bottom right handle in a draw skeleton
*/
.jtk-draw-handle-br {
bottom: 0;
right: 0;
cursor: se-resize;
}
/*
Assigned to the center handle in a draw skeleton (the handle by which the element may be dragged). This is
not visible by defaut; enable if you need it.
*/
.jtk-draw-drag {
display:none;
position: absolute;
left: 50%;
top: 50%;
margin-left: -10px;
margin-top: -10px;
width: 20px;
height: 20px;
background-color: #84acb3;
cursor: move;
}
/*
This class is added to the document body on drag resize start and removed at the end of resizing. Its purpose
is to switch off text selection on all elements while the user is resizing an element.
*/
.jtk-drag-select-defeat * {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}

View File

@@ -43,7 +43,8 @@
@import "library/blue-imp-gallery/_bootstrap-image-gallery"; // Blue Imp Gallery Bootstrap
@import "library/bootstrap-toggle/_bootstrap-toggle"; // Bootstrap Toggle v2.2.0
@import "library/bootstrap-checkbox/_awesome-bootstrap-checkbox"; // Bootstrap Customized Checkboxes v0.3.7 - https://github.com/flatlogic/awesome-bootstrap-checkbox
@import "library/summernote/summernote"; // Summernote WYSIWYG editor v0.8.10
@import "library/summernote/_summernote"; // Summernote WYSIWYG editor v0.8.10
//@import "library/jsplumb/_jsplumbtoolkit-defaults"; // JsPlumb SVG map v2.9.3
// Main THEME (Imports by order - do not change order)
@import "main";