Files
pathfinder/js/app/map/magnetizing.js
Mark Friedrich ee85b1af56 - Improved 'dragSelect' on map, added "autoScroll" while dragging, closed #879
- Fixed system position not saved properly after multiple systems were dragged at once
2019-11-30 12:57:36 +01:00

224 lines
6.9 KiB
JavaScript

/**
* Map "magnetizing" feature
* jsPlumb extension used: https://github.com/ThomasChan/farahey
*/
define([
'jquery',
'app/map/util',
'farahey'
], ($, MapUtil) => {
'use strict';
/**
* active magnetizer instances (cache object)
* @type {{}}
*/
let magnetizerInstances = {};
/**
* magnetizer instance exists for mapId
* @param mapId
* @returns {boolean}
*/
let hasInstance = mapId => magnetizerInstances.hasOwnProperty(mapId);
/**
* get magnetizer instance by mapId
* @param mapId
* @returns {null}
*/
let getInstance = mapId => hasInstance(mapId) ? magnetizerInstances[mapId] : null;
/**
* set new magnetizer instance for mapId
* @param mapId
* @param magnetizer
*/
let setInstance = (mapId, magnetizer) => {
if(mapId && magnetizer){
magnetizerInstances[mapId] = magnetizer;
}
};
/**
* init new magnetizer instance for a map
* @param mapContainer
*/
let initMagnetizer = mapContainer => {
let mapId = mapContainer.data('id');
if(!hasInstance(mapId)){
// magnetizer not exist -> new instance
let systems = mapContainer.getSystems();
/**
* function that takes an element from your list and returns its position as a JS object
* @param system
* @returns {{top: number, left: number}}
* @private
*/
let _offset = system => {
let _ = p => {
let v = system.style[p];
return parseInt(v.substring(0, v.length - 2));
};
return {left: _('left'), top: _('top')};
};
/**
* function that takes an element id and position, and applies that position to the related element
* @param system
* @param o
* @private
*/
let _setOffset = (system, o) => {
o.left = Math.round(o.left);
o.top = Math.round(o.top);
let left = o.left + 'px';
let top = o.top + 'px';
let markAsUpdated = false;
// new position must be within parent container
// no negative offset!
if(
o.left >= 0 && o.left <= 2300 &&
system.style.left !== left
){
system.style.left = left;
markAsUpdated = true;
}
if(
o.top >= 0 && o.top <= 1400 &&
system.style.top !== top
){
system.style.top = top;
markAsUpdated = true;
}
if(markAsUpdated){
MapUtil.markAsChanged($(system));
}
};
/**
* filter some element8s) from being moved
* @param systemId
* @returns {boolean}
* @private
*/
let _dragFilter = systemId => {
let filterClasses = ['jtk-drag', MapUtil.config.systemLockedClass];
return ![...document.getElementById(systemId).classList].some(className => filterClasses.indexOf(className) >= 0);
};
/**
* grid snap constraint
* @param gridX
* @param gridY
* @returns {Function}
*/
let gridConstrain = (gridX, gridY) => {
return (id, current, delta) => {
if(mapContainer.hasClass(MapUtil.config.mapGridClass)){
// active grid
return {
left: (gridX * Math.floor( (Math.round(current[0]) + delta.left) / gridX )) - current[0],
top: (gridY * Math.floor( (Math.round(current[1]) + delta.top) / gridY )) - current[1]
};
}else{
// no grid
delta.left = Math.round(delta.left);
delta.top = Math.round(delta.top);
return delta;
}
};
};
// create new magnetizer instance -------------------------------------------------------------------------
setInstance(mapId, window.Farahey.getInstance({
container: mapContainer,
getContainerPosition: mapContainer => mapContainer.offset(),
getPosition:_offset,
getSize: system => {
let clientRect = system.getBoundingClientRect();
return [Math.floor(clientRect.width), Math.floor(clientRect.height)];
},
getId : system => system.id,
setPosition:_setOffset,
elements: systems.toArray(),
filter: _dragFilter,
padding: [3, 3],
constrain: gridConstrain(MapUtil.config.mapSnapToGridDimension, MapUtil.config.mapSnapToGridDimension),
executeNow: false, // no initial rearrange after initialization
excludeFocus: true
}));
}
};
/**
* destroy Magnetizer instance
*/
let destroyMagnetizer = mapContainer => {
let mapId = mapContainer.data('id');
let magnetizer = getInstance(mapId);
if(magnetizer){
magnetizer.reset();
delete magnetizerInstances[mapId];
}
};
/**
* update system positions for "all" systems that are effected by drag&drop
* @param map
* @param e
*/
let executeAtEvent = (map, e) => {
let mapContainer = $(map.getContainer());
let mapId = mapContainer.data('id');
let magnetizer = getInstance(mapId);
if(magnetizer && e){
magnetizer.executeAtEvent(e, {
iterations: 2,
excludeFocus: true
});
map.repaintEverything();
}
};
/**
* add system to magnetizer instance
* @param mapId
* @param system
* @param doNotTestForDuplicates
*/
let addElement = (mapId, system, doNotTestForDuplicates) => {
let magnetizer = getInstance(mapId);
if(magnetizer){
magnetizer.addElement(system, doNotTestForDuplicates);
}
};
/**
* remove system element from magnetizer instance
* @param mapId
* @param system
*/
let removeElement = (mapId, system) => {
let magnetizer = getInstance(mapId);
if(magnetizer){
magnetizer.removeElement(system);
}
};
return {
initMagnetizer: initMagnetizer,
destroyMagnetizer: destroyMagnetizer,
executeAtEvent: executeAtEvent,
addElement: addElement,
removeElement: removeElement
};
});