diff --git a/app/main/controller/api/map.php b/app/main/controller/api/map.php
index 2758db2f..1fa570a2 100644
--- a/app/main/controller/api/map.php
+++ b/app/main/controller/api/map.php
@@ -878,6 +878,7 @@ class Map extends Controller\AccessController {
$getMapUserData = (bool)$postData['getMapUserData'];
$mapTracking = (bool)$postData['mapTracking'];
$systemData = (array)$postData['systemData'];
+ $newSystemPositions = (array)$postData['newSystemPositions'];
$activeCharacter = $this->getCharacter();
$return = (object)[];
@@ -893,7 +894,7 @@ class Map extends Controller\AccessController {
if( !is_null($map = $activeCharacter->getMap($mapId)) ){
// check character log (current system) and manipulate map (e.g. add new system)
if($mapTracking){
- $map = $this->updateMapByCharacter($map, $activeCharacter);
+ $map = $this->updateMapByCharacter($map, $activeCharacter, $newSystemPositions);
}
// mapUserData ----------------------------------------------------------------------------------------
@@ -938,10 +939,11 @@ class Map extends Controller\AccessController {
* update map connections/systems based on $character´s location logs
* @param Pathfinder\MapModel $map
* @param Pathfinder\CharacterModel $character
+ * @param array $newSystemPositions
* @return Pathfinder\MapModel
* @throws Exception
*/
- protected function updateMapByCharacter(Pathfinder\MapModel $map, Pathfinder\CharacterModel $character) : Pathfinder\MapModel {
+ protected function updateMapByCharacter(Pathfinder\MapModel $map, Pathfinder\CharacterModel $character, array $newSystemPositions = []) : Pathfinder\MapModel {
// map changed. update cache (system/connection) changed
$mapDataChanged = false;
@@ -958,6 +960,9 @@ class Map extends Controller\AccessController {
$sourceSystemId = (int)$sourceLog->systemId;
if($sourceSystemId){
+ $defaultPositions = (array)$newSystemPositions['defaults'];
+ $currentPosition = (array)$newSystemPositions['location'];
+
$sourceSystem = null;
$targetSystem = null;
@@ -969,8 +974,8 @@ class Map extends Controller\AccessController {
// system coordinates for system tha might be added next
$systemOffsetX = 130;
$systemOffsetY = 0;
- $systemPosX = 0;
- $systemPosY = 30;
+ $systemPosX = ((int)$defaultPositions[0]['x']) ? : 0;
+ $systemPosY = ((int)$defaultPositions[0]['y']) ? : 30;
// check if previous (solo) system is already on the map ----------------------------------------------
$sourceSystem = $map->getSystemByCCPId($sourceSystemId, [AbstractModel::getFilter('active', true)]);
@@ -978,12 +983,10 @@ class Map extends Controller\AccessController {
// if systems don´t already exists on map -> get "blank" system
// -> required for system type check (e.g. wormhole, k-space)
if($sourceSystem){
+ // system exists
$sourceExists = true;
-
- // system exists -> add target to the "right"
- $systemPosX = $sourceSystem->posX + $systemOffsetX;
- $systemPosY = $sourceSystem->posY + $systemOffsetY;
}else{
+ // system not exists -> get"blank" system
$sourceSystem = $map->getNewSystem($sourceSystemId);
}
@@ -998,6 +1001,11 @@ class Map extends Controller\AccessController {
if($targetSystem){
$targetExists = true;
+
+ if($targetSystemId === (int)$currentPosition['systemId']){
+ $systemPosX = (int)$currentPosition['position']['x'];
+ $systemPosY = (int)$currentPosition['position']['y'];
+ }
}else{
$targetSystem = $map->getNewSystem($targetSystemId);
}
@@ -1098,9 +1106,15 @@ class Map extends Controller\AccessController {
$map = $sourceSystem->mapId;
$sourceExists = true;
$mapDataChanged = true;
- // increase system position (prevent overlapping)
- $systemPosX = $sourceSystem->posX + $systemOffsetX;
- $systemPosY = $sourceSystem->posY + $systemOffsetY;
+
+ if(!empty($defaultPositions[1])){
+ $systemPosX = (int)$defaultPositions[1]['x'];
+ $systemPosY = (int)$defaultPositions[1]['y'];
+ }else{
+ // increase system position (prevent overlapping)
+ $systemPosX = $sourceSystem->posX + $systemOffsetX;
+ $systemPosY = $sourceSystem->posY + $systemOffsetY;
+ }
}
}
diff --git a/app/main/model/pathfinder/mapmodel.php b/app/main/model/pathfinder/mapmodel.php
index 24aef847..2be5ad10 100644
--- a/app/main/model/pathfinder/mapmodel.php
+++ b/app/main/model/pathfinder/mapmodel.php
@@ -17,6 +17,9 @@ use lib\logging;
class MapModel extends AbstractMapTrackingModel {
+ /**
+ * @var string
+ */
protected $table = 'map';
/**
@@ -27,6 +30,9 @@ class MapModel extends AbstractMapTrackingModel {
const ERROR_SLACK_CHANNEL = 'Invalid #Slack channel column [%s]';
const ERROR_DISCORD_CHANNEL = 'Invalid #Discord channel column [%s]';
+ /**
+ * @var array
+ */
protected $fieldConf = [
'active' => [
'type' => Schema::DT_BOOL,
diff --git a/js/app/map/layout.js b/js/app/map/layout.js
index fcf1f051..2dac71af 100644
--- a/js/app/map/layout.js
+++ b/js/app/map/layout.js
@@ -6,41 +6,50 @@ define(() => {
constructor(config){
this._defaultConfig = {
container: null, // parent DOM container element
- center: null, // DOM elements that works as center
+ center: null, // DOM element OR [x,y] coordinates that works as center
elementClass: 'pf-system', // class for all elements
+ defaultSteps: 8, // how many potential dimensions are checked on en ellipsis around the center
defaultGapX: 50,
defaultGapY: 50,
gapX: 50, // leave gap between elements (x-axis)
gapY: 50, // leave gap between elements (y-axis)
+ minX: 0, // min x for valid elements
+ minY: 0, // min y for valid elements
+ spacingX: 20, // spacing x between elements
+ spacingY: 10, // spacing y between elements
loops: 2, // max loops around "center" for search
grid: false, // set to [20, 20] to force grid snapping
newElementWidth: 100, // width for new element
newElementHeight: 22, // height for new element
+ mirrorSearch: false, // if true coordinates are "mirrored" for an "alternating" search
debug: false, // render debug elements
+ debugOk: false, // if true, only not overlapped dimensions are rendered for debug
debugElementClass: 'pf-system-debug' // class for debug elements
};
this._config = Object.assign({}, this._defaultConfig, config);
+ this._config.dimensionCache = {};
+
+ this._cacheKey = (dim, depth) => ['dim', dim.left, dim.top, dim.width, dim.height, depth].join('_');
+
/**
* convert degree into radial unit
* @param deg
* @returns {number}
* @private
*/
- this._degToRad = (deg) => {
- return deg * Math.PI / 180;
- };
+ this._degToRad = deg => deg * Math.PI / 180;
/**
* get element dimension/position of a DOM element
* @param element
- * @returns {*}
+ * @param spacingX
+ * @param spacingY
+ * @returns {{a: *, b: *, top: *, left: *, width: *, height: *}}
* @private
*/
- this._getElementDimension = element => {
- let dim = null;
-
+ this._getElementDimension = (element, spacingX = 0, spacingY = 0) => {
let left = 0;
let top = 0;
let a = 0;
@@ -49,7 +58,7 @@ define(() => {
let height = this._config.newElementHeight;
if(Array.isArray(element)){
- // xy coordinates
+ // x/y coordinates
let point = [
element[0] ? parseInt(element[0], 10) : 0,
element[1] ? parseInt(element[1], 10) : 0
@@ -63,14 +72,21 @@ define(() => {
top = point[1];
a = this._config.gapX;
b = this._config.gapY;
- }else if(element){
+ }else if(element instanceof Element){
// DOM element
- left = element.style.left ? parseInt(element.style.left, 10) : 0;
- top = element.style.top ? parseInt(element.style.top, 10) : 0;
- a = parseInt((element.offsetWidth / 2).toString(), 10) + this._config.gapX;
- b = parseInt((element.offsetHeight / 2).toString(), 10) + this._config.gapY;
- width = element.offsetWidth;
- height = element.offsetHeight;
+ left = (element.style.left ? parseInt(element.style.left, 10) : 0) - spacingX;
+ top = (element.style.top ? parseInt(element.style.top, 10) : 0) - spacingY;
+ a = parseInt((element.offsetWidth / 2).toString(), 10) + spacingX + this._config.gapX;
+ b = parseInt((element.offsetHeight / 2).toString(), 10) + spacingY + this._config.gapY;
+ width = element.offsetWidth + 2 * spacingX;
+ height = element.offsetHeight + 2 * spacingY;
+ }else if(element instanceof Object){
+ left = element.left - spacingX;
+ top = element.top - spacingY;
+ a = parseInt((element.width / 2).toString(), 10) + spacingX + this._config.gapX;
+ b = parseInt((element.height / 2).toString(), 10) + spacingY + this._config.gapY;
+ width = element.width + 2 * spacingX;
+ height = element.height + 2 * spacingY;
}
// add "gap" to a and b in order to have some space around elements
@@ -121,7 +137,7 @@ define(() => {
let dimensions = [];
let surroundingElements = this._getContainer().getElementsByClassName(this._config.elementClass);
for(let element of surroundingElements){
- dimensions.push(this._getElementDimension(element));
+ dimensions.push(this._getElementDimension(element, this._config.spacingX, this._config.spacingY));
}
return dimensions;
};
@@ -132,7 +148,7 @@ define(() => {
* @returns {*}
* @private
*/
- this._transformPointToGrid = (point) => {
+ this._transformPointToGrid = point => {
point[0] = Math.floor(point[0] / this._config.grid[0]) * this._config.grid[0];
point[1] = Math.floor(point[1] / this._config.grid[1]) * this._config.grid[1];
return point;
@@ -231,31 +247,44 @@ define(() => {
return percent;
};
+ /**
+ * checks whether dim11 has valid x/y coordinate
+ * -> coordinates are >= "minX/Y" limit
+ * @param dim1
+ * @returns {*|boolean}
+ * @private
+ */
+ this._valid = dim1 => dim1 && dim1.left >= this._config.minX && dim1.top >= this._config.minY;
+
/**
* checks whether dim1 is partially overlapped by any other element
* @param dim1
* @param dimensionContainer
* @param allDimensions
+ * @param depth
* @returns {boolean}
* @private
*/
- this._isOverlapping = (dim1, dimensionContainer, allDimensions) => {
+ this._isOverlapping = (dim1, dimensionContainer, allDimensions, depth) => {
let isOverlapping = false;
if(dim1){
- if(this._percentCovered(dimensionContainer, dim1 ) === 100){
+ let cacheKey = this._cacheKey(dim1, depth);
+ // check cache first (e.g. if grid is active some dimensions would be checked multiple times)
+ if(this._config.dimensionCache[cacheKey]){
+ return true;
+ }else if(this._percentCovered(dimensionContainer, dim1) === 100){
// element is within parent container
for(let dim2 of allDimensions){
let percentCovered = this._percentCovered(dim1, dim2);
if(percentCovered){
isOverlapping = true;
- // render debug element
- this._showDebugElement(dim1, percentCovered);
+ this._config.dimensionCache[cacheKey] = percentCovered;
break;
}
}
}else{
isOverlapping = true;
- this._showDebugElement(dim1, 100);
+ this._config.dimensionCache[cacheKey] = 100;
}
}else{
isOverlapping = true;
@@ -264,36 +293,63 @@ define(() => {
return isOverlapping;
};
+ /**
+ *
+ * @param dim1
+ * @returns {boolean}
+ * @private
+ */
+ this._existDimension = function(dim1){
+ return (
+ dim1.left === this.left &&
+ dim1.top === this.top &&
+ dim1.width === this.width &&
+ dim1.height === this.height
+ );
+ };
+
/**
* find all dimensions around a centerDimension that are not overlapped by other elements
* @param maxResults
* @param steps
* @param allDimensions
+ * @param depth
* @param loops
* @returns {Array}
* @private
*/
- this._findDimensions = (maxResults, steps, allDimensions, loops) => {
+ this._findDimensions = (maxResults, steps, allDimensions, depth, loops) => {
+ steps = steps || 1;
+ loops = loops || 1;
+
let dimensions = [];
let start = 0;
let end = 360;
let angle = end / steps;
+
+ // as default coordinates get checked clockwise Q4 -> Q3 -> Q2 -> Q1
+ // we could also check "mirrored" coordinates Q4+Q1 -> Q3+Q2
+ if(this._config.mirrorSearch){
+ end /= end;
+ }
+
let dimensionContainer = this._getElementDimension(this._getContainer());
- steps = steps || 1;
- loops = loops || 1;
if(loops === 1){
// check center element
let centerDimension = this._getElementDimension(this._config.center);
- if(!this._isOverlapping(centerDimension, dimensionContainer, allDimensions)){
+ if(
+ this._valid(centerDimension) &&
+ !dimensions.some(this._existDimension, centerDimension) &&
+ !this._isOverlapping(centerDimension, dimensionContainer, allDimensions, depth)
+ ){
dimensions.push({
left: centerDimension.left,
top: centerDimension.top,
width: centerDimension.width,
height: centerDimension.height
});
- // render debug element
- this._showDebugElement(centerDimension, 0);
+ this._config.dimensionCache[this._cacheKey(centerDimension, depth)] = 0;
maxResults--;
}
@@ -308,27 +364,38 @@ define(() => {
while(maxResults > 0 && start < end){
// get all potential coordinates on an eclipse around a given "centerElementDimension"
let coordinate = this._getEllipseCoordinates(centerDimension, end);
- // transform relative x/y coordinate into a absolute 2D area
- let checkDimension = this._transformCoordinate(centerDimension, coordinate);
- if(!this._isOverlapping(checkDimension, dimensionContainer, allDimensions)){
- dimensions.push({
- left: checkDimension.left,
- top: checkDimension.top,
- width: checkDimension.width,
- height: checkDimension.height
- });
- // render debug element
- this._showDebugElement(checkDimension, 0);
-
- maxResults--;
+ let coordinates = [coordinate];
+ if(this._config.mirrorSearch && coordinate){
+ coordinates.push({x: coordinate.x, y: coordinate.y * -1 });
}
+
+ for(let coordinateTemp of coordinates){
+ // transform relative x/y coordinate into a absolute 2D area
+ let checkDimension = this._transformCoordinate(centerDimension, coordinateTemp);
+ if(
+ this._valid(checkDimension) &&
+ !dimensions.some(this._existDimension, checkDimension) &&
+ !this._isOverlapping(checkDimension, dimensionContainer, allDimensions, depth)
+ ){
+ dimensions.push({
+ left: checkDimension.left,
+ top: checkDimension.top,
+ width: checkDimension.width,
+ height: checkDimension.height
+ });
+ this._config.dimensionCache[this._cacheKey(checkDimension, depth)] = 0;
+
+ maxResults--;
+ }
+ }
+
end -= angle;
}
if(maxResults > 0 && loops < this._config.loops){
loops++;
steps *= 2;
- dimensions = dimensions.concat(this._findDimensions(maxResults, steps, allDimensions, loops));
+ dimensions = dimensions.concat(this._findDimensions(maxResults, steps, allDimensions, depth, loops));
}
return dimensions;
@@ -346,21 +413,33 @@ define(() => {
/**
* render debug element into parent container
* -> checks overlapping dimension with other elements
- * @param dimension
- * @param percentCovered
* @private
*/
- this._showDebugElement = (dimension, percentCovered) => {
+ this._showDebugElements = () => {
if(this._config.debug){
- let element = document.createElement('div');
- element.style.left = dimension.left + 'px';
- element.style.top = dimension.top + 'px';
- element.style.width = dimension.width + 'px';
- element.style.height = dimension.height + 'px';
- element.style.backgroundColor = Boolean(percentCovered) ? 'rgba(255,0,0,0.1)' : 'rgba(0,255,0,0.1)';
- element.innerHTML = Math.round(percentCovered * 100) / 100 + '%';
- element.classList.add(this._config.debugElementClass);
- this._getContainer().appendChild(element);
+ let documentFragment = document.createDocumentFragment();
+ for(let [cacheKey, percentCovered] of Object.entries(this._config.dimensionCache)){
+ if(this._config.debugOk && percentCovered){
+ continue;
+ }
+
+ let element = document.createElement('div');
+ let dimParts = cacheKey.split('_');
+ element.style.left = dimParts[1] + 'px';
+ element.style.top = dimParts[2] + 'px';
+ element.style.width = dimParts[3] + 'px';
+ element.style.height = dimParts[4] + 'px';
+ element.style.backgroundColor = Boolean(percentCovered) ? 'rgba(255,0,0,0.1)' : 'rgba(0,255,0,0.4)';
+ element.style.opacity = Boolean(percentCovered) ? 0.5 : 1;
+ element.style.zIndex = Boolean(percentCovered) ? 1000 : 2000;
+ element.style.border = Boolean(percentCovered) ? 'none' : '1px solid rgba(0,255,0,0.3)';
+ element.innerHTML = Math.round(percentCovered * 100) / 100 + '';
+ element.classList.add(this._config.debugElementClass);
+ element.setAttribute('data-depth', dimParts[5]);
+ documentFragment.appendChild(element);
+ }
+
+ this._getContainer().appendChild(documentFragment);
}
};
@@ -381,15 +460,45 @@ define(() => {
/**
* search for surrounding, non overlapping dimensions
* @param maxResults
- * @param steps
+ * @param findChain
* @returns {Array}
*/
- this.findNonOverlappingDimensions = (maxResults, steps) => {
+ this.findNonOverlappingDimensions = (maxResults, findChain = false) => {
this._hideDebugElements();
+ this._config.dimensionCache = {};
+
// element dimensions that exist and should be checked for overlapping
let allDimensions = this._getAllElementDimensions();
+ let dimensions = [];
+ let depth = 1;
+ let maxDepth = findChain ? maxResults : 1;
+ maxResults = findChain ? 1 : maxResults;
+ while(depth <= maxDepth){
+ let dimensionsTemp = this._findDimensions(maxResults, this._config.defaultSteps, allDimensions, depth);
- return this._findDimensions(maxResults, steps, allDimensions);
+ if(dimensionsTemp.length){
+ dimensions = dimensions.concat(dimensionsTemp);
+
+ if(findChain){
+ // if depth > 0 we have 2D dimension as "center" (not a x/y coordinate)
+ // -> increase the gap
+ this._config.defaultGapX = 10;
+ this._config.defaultGapY = 10;
+ this._config.gapX = 50;
+ this._config.gapY = 50;
+ this._config.center = dimensionsTemp[0];
+ allDimensions = allDimensions.concat([this._getElementDimension(dimensionsTemp[0], this._config.spacingX, this._config.spacingY)]);
+ }
+
+ depth++;
+ }else{
+ break;
+ }
+ }
+
+ this._showDebugElements();
+
+ return dimensions;
};
}
}
diff --git a/js/app/map/map.js b/js/app/map/map.js
index ac68255f..0dfcbbc9 100644
--- a/js/app/map/map.js
+++ b/js/app/map/map.js
@@ -662,20 +662,10 @@ define([
case 'add_system':
// add new system dialog
let position = Layout.getEventCoordinates(e);
-
- let grid = [MapUtil.config.mapSnapToGridDimension, MapUtil.config.mapSnapToGridDimension];
- let positionFinder = new Layout.Position({
- container: mapElement[0],
- center: [position.x, position.y],
- loops: 5,
- defaultGapX: 10,
- defaultGapY: 10,
- grid: mapElement.hasClass(MapUtil.config.mapGridClass) ? grid : false,
- debug: false
+ let dimensions = MapUtil.newSystemPositionByCoordinates(mapElement, {
+ center: [position.x, position.y]
});
- let dimensions = positionFinder.findNonOverlappingDimensions(1, 8);
-
if(dimensions.length){
position.x = dimensions[0].left;
position.y = dimensions[0].top;
diff --git a/js/app/map/system.js b/js/app/map/system.js
index beffcfc1..e287b552 100644
--- a/js/app/map/system.js
+++ b/js/app/map/system.js
@@ -9,9 +9,8 @@ define([
'app/util',
'bootbox',
'app/map/util',
- 'app/map/layout',
'app/map/magnetizing'
-], ($, Init, Util, bootbox, MapUtil, Layout, Magnetizer) => {
+], ($, Init, Util, bootbox, MapUtil, Magnetizer) => {
'use strict';
let config = {
@@ -245,7 +244,7 @@ define([
sourceSystem = options.sourceSystem;
// get new position
- newPosition = calculateNewSystemPosition(sourceSystem);
+ newPosition = newSystemPositionBySystem(sourceSystem);
}else if(options.position){
// check mouse cursor position (add system to map)
newPosition = {
@@ -730,25 +729,16 @@ define([
};
/**
- * calculate the x/y coordinates for a new system - relativ to a source system
+ * calculate the x/y coordinates for a new system - relative to a source system
+ * -> in case no coordinates found -> return default calculated coordinates
* @param sourceSystem
* @returns {{x: *, y: *}}
*/
- let calculateNewSystemPosition = sourceSystem => {
- let mapContainer = sourceSystem.parent();
- let grid = [MapUtil.config.mapSnapToGridDimension, MapUtil.config.mapSnapToGridDimension];
+ let newSystemPositionBySystem = sourceSystem => {
let x = 0;
let y = 0;
- let positionFinder = new Layout.Position({
- container: mapContainer[0],
- center: sourceSystem[0],
- loops: 4,
- grid: mapContainer.hasClass(MapUtil.config.mapGridClass) ? grid : false,
- debug: false
- });
-
- let dimensions = positionFinder.findNonOverlappingDimensions(1, 16);
+ let dimensions = MapUtil.newSystemPositionBySystem(sourceSystem);
if(dimensions.length){
//... empty map space found
x = dimensions[0].left;
diff --git a/js/app/map/util.js b/js/app/map/util.js
index b2c925de..807d808c 100644
--- a/js/app/map/util.js
+++ b/js/app/map/util.js
@@ -6,9 +6,10 @@ define([
'jquery',
'app/init',
'app/util',
+ 'app/map/layout',
'app/map/scrollbar',
'app/map/overlay/util'
-], ($, Init, Util, Scrollbar, MapOverlayUtil) => {
+], ($, Init, Util, Layout, Scrollbar, MapOverlayUtil) => {
'use strict';
let config = {
@@ -2112,6 +2113,132 @@ define([
return hasAccess;
};
+ /**
+ *
+ * @param options
+ * @param maxResults
+ * @param findChain
+ * @returns {Array}
+ */
+ let findNonOverlappingDimensions = (options = {}, maxResults = 1, findChain = false) => {
+ let defaultOptions = {
+ center: [0, 30],
+ loops: 4,
+ debug: false
+ };
+
+ options = Object.assign({}, defaultOptions, options);
+ let positionFinder = new Layout.Position(Object.assign({}, defaultOptions, options));
+
+ return positionFinder.findNonOverlappingDimensions(maxResults, findChain);
+ };
+
+ /**
+ * calculate the x/y coordinates for a new system - relative to a source system
+ * @param sourceSystem
+ * @returns {Array}
+ */
+ let newSystemPositionBySystem = sourceSystem => {
+ let mapContainer = sourceSystem.parent();
+ let grid = [config.mapSnapToGridDimension, config.mapSnapToGridDimension];
+
+ let options = {
+ container: mapContainer[0],
+ center: sourceSystem[0],
+ grid: mapContainer.hasClass(config.mapGridClass) ? grid : false
+ };
+
+ return findNonOverlappingDimensions(options);
+ };
+
+ /**
+ * calculate the x/y coordinates for a new system - relative to x/y position
+ * @param mapContainer
+ * @param options
+ * @param maxResults
+ * @param findChain
+ * @returns {Array}
+ */
+ let newSystemPositionByCoordinates = (mapContainer, options = {}, maxResults = 1, findChain = false) => {
+ let grid = [config.mapSnapToGridDimension, config.mapSnapToGridDimension];
+
+ let defaultOptions = {
+ container: mapContainer[0],
+ center: [0, 0],
+ grid: mapContainer.hasClass(config.mapGridClass) ? grid : false,
+ loops: 10,
+ defaultGapX: 10,
+ defaultGapY: 10,
+ //debugOk: true,
+ //debug: true
+ };
+
+ options = Object.assign({}, defaultOptions, options);
+
+ return findNonOverlappingDimensions(options, maxResults, findChain);
+ };
+
+ /**
+ *
+ * @param mapContainer
+ */
+ let newSystemPositionsByMap = mapContainer => {
+ let positions = {};
+
+ if(mapContainer){
+ let mapId = mapContainer.data('id');
+ let scrollPosition = {
+ x: Math.abs(parseInt(mapContainer.attr('data-scroll-left')) || 0),
+ y: Math.abs(parseInt(mapContainer.attr('data-scroll-top')) || 0)
+ };
+
+ // space new positions from map top (e.g. used for tooltips)
+ scrollPosition.y = Math.max(scrollPosition.y, 30);
+
+ // default position -> current map section top/left -------------------------------------------------------
+ positions.defaults = [scrollPosition];
+
+ // check default position for overlapping -----------------------------------------------------------------
+ let dimensions = newSystemPositionByCoordinates(mapContainer, {
+ center: [scrollPosition.x, scrollPosition.y],
+ minX: scrollPosition.x,
+ minY: scrollPosition.y
+ }, 2, true);
+
+ if(dimensions.length){
+ positions.defaults = dimensions.map(dim => ({
+ x: parseInt(dim.left) || 0,
+ y: parseInt(dim.top) || 0
+ }));
+ }
+
+ // -> calc possible coordinates for new system that should be used based on current user location ---------
+ let currentLocationData = Util.getCurrentLocationData();
+ if(currentLocationData.id){
+ // ... we need to the PF systemId for 'SelectSystem' trigger
+ let systemData = getSystemData(mapId, currentLocationData.id, 'systemId');
+ if(systemData){
+ let currentSystem = $('#' + getSystemId(mapId, systemData.id));
+ if(currentSystem.length){
+ let dimensions = newSystemPositionBySystem(currentSystem);
+ if(dimensions.length){
+ //... empty map space found
+ positions.location = {
+ systemId: currentLocationData.id,
+ position: {
+ x: dimensions[0].left,
+ y: dimensions[0].top
+ }
+ };
+ }
+ }
+ }
+ }
+ }
+
+ return Object.keys(positions).length ? positions : null;
+ };
+
/**
* get a unique map url for deeplinking
* @param mapId
@@ -2191,6 +2318,9 @@ define([
initWormholeInfoTooltip: initWormholeInfoTooltip,
getSystemId: getSystemId,
checkRight: checkRight,
+ newSystemPositionBySystem: newSystemPositionBySystem,
+ newSystemPositionByCoordinates: newSystemPositionByCoordinates,
+ newSystemPositionsByMap: newSystemPositionsByMap,
getMapDeeplinkUrl: getMapDeeplinkUrl
};
});
\ No newline at end of file
diff --git a/js/app/mappage.js b/js/app/mappage.js
index cdd12e16..e129b841 100644
--- a/js/app/mappage.js
+++ b/js/app/mappage.js
@@ -9,10 +9,11 @@ define([
'app/logging',
'app/page',
'app/map/worker',
+ 'app/map/util',
'app/module_map',
'app/key',
'app/ui/form_element'
-], ($, Init, Util, Logging, Page, MapWorker, ModuleMap) => {
+], ($, Init, Util, Logging, Page, MapWorker, MapUtil, ModuleMap) => {
'use strict';
@@ -464,11 +465,13 @@ define([
// IMPORTANT: Get user data for ONE map that is currently visible
// On later releases this can be easy changed to "full update" all maps for a user
- //
let mapIds = [];
+ let newSystemPositions = null;
let activeMap = Util.getMapModule().getActiveMap();
+
if(activeMap){
- mapIds = [ activeMap.data('id') ];
+ mapIds = [activeMap.data('id')];
+ newSystemPositions = MapUtil.newSystemPositionsByMap(activeMap);
}
let updatedUserData = {
@@ -478,6 +481,10 @@ define([
systemData: Util.getCurrentSystemData()
};
+ if(newSystemPositions){
+ updatedUserData.newSystemPositions = newSystemPositions;
+ }
+
Util.timeStart(logKeyServerUserData);
$.ajax({
diff --git a/js/app/ui/module/system_info.js b/js/app/ui/module/system_info.js
index 71d25e13..05a77c6d 100644
--- a/js/app/ui/module/system_info.js
+++ b/js/app/ui/module/system_info.js
@@ -208,17 +208,17 @@ define([
url = 'https://client'; // fake url
break;
case 'dotlan':
- systemName = systemName.replace(/ /g, '_');
- regionName = regionName.replace(/ /g, '_');
+ let systemNameTemp = systemName.replace(/ /g, '_');
+ let regionNameTemp = regionName.replace(/ /g, '_');
if(isWormhole){
- url = domain + '/system/' + systemName;
+ url = domain + '/system/' + systemNameTemp;
}else{
- url = domain + '/map/' + regionName + '/' + systemName;
+ url = domain + '/map/' + regionNameTemp + '/' + systemNameTemp;
}
break;
case 'eveeye':
if(!isWormhole){
- url = domain + '/?m=' + encodeURIComponent(regionName) + '&s=' + encodeURIComponent(systemName.replace(/ /g, '_'));
+ url = domain + '/?m=' + encodeURIComponent(regionName) + '&s=' + encodeURIComponent(systemName);
url += '&t=eswkc&o=thera,con_svc,node_sov,sub_sec,sector_fac,tag_mk';
}
break;
diff --git a/js/app/ui/module/system_intel.js b/js/app/ui/module/system_intel.js
index 56fbe8bf..6b3b9459 100644
--- a/js/app/ui/module/system_intel.js
+++ b/js/app/ui/module/system_intel.js
@@ -530,7 +530,7 @@ define([
'
' +
' | ' +
'' +
- ' ' +
+ ' ' +
' | ' +
'' + group.name + ' | ' +
'
'
@@ -641,7 +641,7 @@ define([
_: function(data, type, row, meta){
let value = data;
if(type === 'display' && value){
- value = '
';
+ value = '
';
}
return value;
}
@@ -675,7 +675,7 @@ define([
let value = data;
if(type === 'display' && value){
value = '';
- value += '
';
+ value += '
';
value += '';
}
return value;
@@ -869,7 +869,7 @@ define([
_: function(data, type, row, meta){
let value = data;
if(type === 'display' && value){
- value = '
';
+ value = '
';
}
return value;
}
@@ -885,8 +885,11 @@ define([
_: function(cellData, type, rowData, meta){
let value = '';
if(cellData){
- let matches = /^(?[a-z0-9\s\-]+) (?[MDCLXVI]+) .*$/i.exec(cellData);
- let count = Util.getObjVal(matches, 'groups.count');
+ // "grouped" regex not supported by FF
+ // let matches = /^(?[a-z0-9\s\-]+) (?[MDCLXVI]+) .*$/i.exec(cellData);
+ // let count = Util.getObjVal(matches, 'groups.count');
+ let matches = /^([a-z0-9\s\-]+) ([MDCLXVI]+) .*$/i.exec(cellData);
+ let count = Util.getObjVal(matches, '2');
if(type === 'display'){
value = count || 0;
@@ -908,17 +911,19 @@ define([
_: function(cellData, type, rowData, meta){
let value = cellData;
if(cellData){
- let matches = /^(?[a-z0-9\s\-]+) (?[MDCLXVI]+) (?