- Improved auto added system positioning, reduces overlapping, closed #845

This commit is contained in:
Mark Friedrich
2019-10-05 14:23:20 +02:00
parent 3f724f66ce
commit 74cbbec328
20 changed files with 721 additions and 227 deletions

View File

@@ -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;
}
}
}

View File

@@ -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,

View File

@@ -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;
};
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
};
});

View File

@@ -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({

View File

@@ -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;

View File

@@ -530,7 +530,7 @@ define([
'<tr class="group">' +
'<td></td>' +
'<td class="text-right ' + config.tableCellImageClass + '">' +
'<img src="' + Util.eveImageUrl(imgType, group.id) + '"/>' +
'<img src="' + Util.eveImageUrl(imgType, group.id, 64) + '"/>' +
'</td>' +
'<td colspan="' + Math.max((columnCount - 2), 1) + '">' + group.name + '</td>' +
'</tr>'
@@ -641,7 +641,7 @@ define([
_: function(data, type, row, meta){
let value = data;
if(type === 'display' && value){
value = '<img src="' + Util.eveImageUrl('type', value) +'"/>';
value = '<img src="' + Util.eveImageUrl('type', value, 64) +'"/>';
}
return value;
}
@@ -675,7 +675,7 @@ define([
let value = data;
if(type === 'display' && value){
value = '<a href="https://zkillboard.com/corporation/' + data + '/" target="_blank" rel="noopener">';
value += '<img src="' + Util.eveImageUrl('corporation', data) + '"/>';
value += '<img src="' + Util.eveImageUrl('corporation', data, 64) + '"/>';
value += '</a>';
}
return value;
@@ -869,7 +869,7 @@ define([
_: function(data, type, row, meta){
let value = data;
if(type === 'display' && value){
value = '<img src="' + Util.eveImageUrl('type', value) +'"/>';
value = '<img src="' + Util.eveImageUrl('type', value, 64) +'"/>';
}
return value;
}
@@ -885,8 +885,11 @@ define([
_: function(cellData, type, rowData, meta){
let value = '';
if(cellData){
let matches = /^(?<system>[a-z0-9\s\-]+) (?<count>[MDCLXVI]+) .*$/i.exec(cellData);
let count = Util.getObjVal(matches, 'groups.count');
// "grouped" regex not supported by FF
// let matches = /^(?<system>[a-z0-9\s\-]+) (?<count>[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 = /^(?<system>[a-z0-9\s\-]+) (?<count>[MDCLXVI]+) (?<label>\(\w+\)\s)?\- (?<moon>moon (?<moonCount>\d)+)?.*$/i.exec(cellData);
let systemName = Util.getObjVal(matches, 'groups.system');
let count = Util.getObjVal(matches, 'groups.count');
let moon = Util.getObjVal(matches, 'groups.moon');
// "grouped" regex not supported by FF
// let matches = /^(?<system>[a-z0-9\s\-]+) (?<count>[MDCLXVI]+) (?<label>\(\w+\)\s)?\- (?<moon>moon (?<moonCount>\d)+)?.*$/i.exec(cellData);
let matches = /^([a-z0-9\s\-]+) ([MDCLXVI]+) (\(\w+\)\s)?\- (moon (\d)+)?.*$/i.exec(cellData);
let systemName = Util.getObjVal(matches, '1');
let count = Util.getObjVal(matches, '2');
let moon = Util.getObjVal(matches, '4');
if(systemName === (Util.getObjVal(systemData, 'name') || '')){
value = value.slice(systemName.length).trim();
if(count){
value = value.slice(count.length).trimLeftChars(' \-');
}
if(moon){
let moonCount = Util.getObjVal(matches, 'groups.moonCount');
let moonCount = Util.getObjVal(matches, '5');
value = value.replace(moon, 'M' + moonCount);
}
}
@@ -960,7 +965,7 @@ define([
let value = data;
if(type === 'display' && value){
value = '<a href="https://zkillboard.com/corporation/' + data + '/" target="_blank" rel="noopener">';
value += '<img src="' + Util.eveImageUrl('corporation', data) + '"/>';
value += '<img src="' + Util.eveImageUrl('corporation', data, 64) + '"/>';
value += '</a>';
}
return value;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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;
};
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
};
});

View File

@@ -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({

View File

@@ -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;

View File

@@ -530,7 +530,7 @@ define([
'<tr class="group">' +
'<td></td>' +
'<td class="text-right ' + config.tableCellImageClass + '">' +
'<img src="' + Util.eveImageUrl(imgType, group.id) + '"/>' +
'<img src="' + Util.eveImageUrl(imgType, group.id, 64) + '"/>' +
'</td>' +
'<td colspan="' + Math.max((columnCount - 2), 1) + '">' + group.name + '</td>' +
'</tr>'
@@ -641,7 +641,7 @@ define([
_: function(data, type, row, meta){
let value = data;
if(type === 'display' && value){
value = '<img src="' + Util.eveImageUrl('type', value) +'"/>';
value = '<img src="' + Util.eveImageUrl('type', value, 64) +'"/>';
}
return value;
}
@@ -675,7 +675,7 @@ define([
let value = data;
if(type === 'display' && value){
value = '<a href="https://zkillboard.com/corporation/' + data + '/" target="_blank" rel="noopener">';
value += '<img src="' + Util.eveImageUrl('corporation', data) + '"/>';
value += '<img src="' + Util.eveImageUrl('corporation', data, 64) + '"/>';
value += '</a>';
}
return value;
@@ -869,7 +869,7 @@ define([
_: function(data, type, row, meta){
let value = data;
if(type === 'display' && value){
value = '<img src="' + Util.eveImageUrl('type', value) +'"/>';
value = '<img src="' + Util.eveImageUrl('type', value, 64) +'"/>';
}
return value;
}
@@ -885,8 +885,11 @@ define([
_: function(cellData, type, rowData, meta){
let value = '';
if(cellData){
let matches = /^(?<system>[a-z0-9\s\-]+) (?<count>[MDCLXVI]+) .*$/i.exec(cellData);
let count = Util.getObjVal(matches, 'groups.count');
// "grouped" regex not supported by FF
// let matches = /^(?<system>[a-z0-9\s\-]+) (?<count>[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 = /^(?<system>[a-z0-9\s\-]+) (?<count>[MDCLXVI]+) (?<label>\(\w+\)\s)?\- (?<moon>moon (?<moonCount>\d)+)?.*$/i.exec(cellData);
let systemName = Util.getObjVal(matches, 'groups.system');
let count = Util.getObjVal(matches, 'groups.count');
let moon = Util.getObjVal(matches, 'groups.moon');
// "grouped" regex not supported by FF
// let matches = /^(?<system>[a-z0-9\s\-]+) (?<count>[MDCLXVI]+) (?<label>\(\w+\)\s)?\- (?<moon>moon (?<moonCount>\d)+)?.*$/i.exec(cellData);
let matches = /^([a-z0-9\s\-]+) ([MDCLXVI]+) (\(\w+\)\s)?\- (moon (\d)+)?.*$/i.exec(cellData);
let systemName = Util.getObjVal(matches, '1');
let count = Util.getObjVal(matches, '2');
let moon = Util.getObjVal(matches, '4');
if(systemName === (Util.getObjVal(systemData, 'name') || '')){
value = value.slice(systemName.length).trim();
if(count){
value = value.slice(count.length).trimLeftChars(' \-');
}
if(moon){
let moonCount = Util.getObjVal(matches, 'groups.moonCount');
let moonCount = Util.getObjVal(matches, '5');
value = value.replace(moon, 'M' + moonCount);
}
}
@@ -960,7 +965,7 @@ define([
let value = data;
if(type === 'display' && value){
value = '<a href="https://zkillboard.com/corporation/' + data + '/" target="_blank" rel="noopener">';
value += '<img src="' + Util.eveImageUrl('corporation', data) + '"/>';
value += '<img src="' + Util.eveImageUrl('corporation', data, 64) + '"/>';
value += '</a>';
}
return value;

View File

@@ -534,7 +534,18 @@ $mapBubbleWidth: 30px;
line-height: 22px;
text-align: center;
pointer-events: none;
font-family: Oxygen, Arial, sans-serif;
z-index: 500;
&:before{
content: attr(data-depth);
font-family: Oxygen, Arial, sans-serif;
position: absolute;
line-height: 10px;
top: 1px;
left: 2px;
color: $black;
}
}
// Endpoints ========================================================================================================

View File

@@ -160,5 +160,6 @@
.well{
margin-bottom: 0; // overwrite default
line-height: 13px;
}
}