From 74cbbec328b98bf7cb51a3ac877f04ccd8615dc6 Mon Sep 17 00:00:00 2001 From: Mark Friedrich Date: Sat, 5 Oct 2019 14:23:20 +0200 Subject: [PATCH] - Improved auto added system positioning, reduces overlapping, closed #845 --- app/main/controller/api/map.php | 36 ++- app/main/model/pathfinder/mapmodel.php | 6 + js/app/map/layout.js | 225 +++++++++++++----- js/app/map/map.js | 14 +- js/app/map/system.js | 22 +- js/app/map/util.js | 132 +++++++++- js/app/mappage.js | 13 +- js/app/ui/module/system_info.js | 10 +- js/app/ui/module/system_intel.js | 29 ++- public/css/v1.5.4/pathfinder.css | 2 +- public/css/v1.5.4/pathfinder.css.map | 2 +- public/js/v1.5.4/app/map/layout.js | 225 +++++++++++++----- public/js/v1.5.4/app/map/map.js | 14 +- public/js/v1.5.4/app/map/system.js | 22 +- public/js/v1.5.4/app/map/util.js | 132 +++++++++- public/js/v1.5.4/app/mappage.js | 13 +- public/js/v1.5.4/app/ui/module/system_info.js | 10 +- .../js/v1.5.4/app/ui/module/system_intel.js | 29 ++- sass/layout/_map.scss | 11 + sass/layout/_popover.scss | 1 + 20 files changed, 721 insertions(+), 227 deletions(-) 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]+) (?