Files
pathfinder/js/app/map/scrollbar.js
2019-07-29 19:01:55 +02:00

192 lines
5.6 KiB
JavaScript

define([
'jquery',
'mousewheel',
'customScrollbar'
], ($) => {
'use strict';
let defaultConfig = {
axis: 'yx',
theme: 'light-3' ,
scrollInertia: 200,
autoExpandScrollbar: false,
scrollButtons:{
enable: true,
scrollAmount: 30,
scrollType: 'stepless'
},
callbacks: {
onTotalScrollOffset: 0,
onTotalScrollBackOffset: 0,
alwaysTriggerOffsets: true
},
advanced: {
autoUpdateTimeout: 120, // auto-update timeout (default: 60)
updateOnContentResize: true,
autoExpandHorizontalScroll: false, // on resize css scale() scroll content should not change
//autoExpandHorizontalScroll: 2,
autoScrollOnFocus: 'div',
},
mouseWheel: {
enable: false, // scroll wheel currently disabled
scrollAmount: 'auto',
axis: 'x',
preventDefault: true
},
keyboard: {
enable: false, // not working with pathfinder "shortcuts"
scrollType: 'stepless',
scrollAmount: 'auto'
},
scrollbarPosition: 'inside',
autoDraggerLength: true,
autoHideScrollbar: false
};
/**
* init map scrollbar
* @param scrollWrapper
* @param config
*/
let initScrollbar = (scrollWrapper, config) => {
config = $.extend(true, {}, defaultConfig, config);
scrollWrapper.mCustomScrollbar(config);
};
/**
* get mCustomScrollbar container
* @param element
* @returns {*|[]}
*/
let getContainer = element => element.parents('.mCSB_container');
/**
*
* @param container
* @param element
* @returns {{x: number, y: number}}
*/
let getElementPos = (container, element) => {
return {
x: element.offset().left - container.offset().left,
y: element.offset().top - container.offset().top
};
};
/**
* @param element
* @returns {{x: number, y: number}}
*/
let getElementDim = element => {
return {
x: element.outerWidth(false),
y: element.outerHeight(false)
};
};
/**
* check if an element is 100% visible
* -> scrolled into viewport
* @param element
* @returns {boolean}
*/
let isInView = element => {
let container = getContainer(element);
let wrapper = container.parent();
let cPos = {x: container[0].offsetLeft, y: container[0].offsetTop};
let ePos = getElementPos(container, element);
let eDim = getElementDim(element);
return cPos.y + ePos.y >= 0 &&
cPos.y + ePos.y < wrapper.height() - eDim.y &&
cPos.x + ePos.x >= 0 &&
cPos.x + ePos.x < wrapper.width() - eDim.x;
};
/**
* get new scrollTo coordinates to center element in viewport
* @param element
* @returns {{x: number, y: number}}
*/
let getCenterScrollPosition = element => {
let container = getContainer(element);
let wrapper = container.parent();
let cDim = getElementDim(container);
let wDim = {x: wrapper.width(), y: wrapper.height()};
let eDim = getElementDim(element);
let ePos = getElementPos(container, element);
let eOff = {
x: (-wDim.x / 2) + (eDim.x / 2),
y: (-wDim.y / 2) + (eDim.y / 2)
};
return adjustPos(addOffset(ePos, eOff), cDim);
};
/**
* scroll to a specific position on map
* demo: http://manos.malihu.gr/repository/custom-scrollbar/demo/examples/scrollTo_demo.html
* @param scrollWrapper
* @param position
* @param options
*/
let scrollToPosition = (scrollWrapper, position, options) => {
$(scrollWrapper).mCustomScrollbar('scrollTo', position, options);
};
/**
* scroll to center an element
* -> subtract some offset for tooltips/connections
* @param scrollWrapper
* @param element
*/
let scrollToCenter = (scrollWrapper, element) => {
// no scroll if element is already FULL visible in scrollable viewport
if(!isInView(element)){
// get scrollTo position for centered element
scrollToPosition(scrollWrapper, getCenterScrollPosition(element));
}
};
/**
* add/subtract offset coordinates from position
* @param {{x: number, y: number}} position
* @param {{x: number, y: number}} offset
* @returns {{x: number, y: number}}
*/
let addOffset = (position, offset) => mapObject(position, (v, k) => v + offset[k]);
/**
* round position
* @param {{x: number, y: number}} position
* @returns {{x: number, y: number}}
*/
let roundPos = position => mapObject(position, Math.round);
/**
*
* @param {{x: number, y: number}} position
* @param {{x: number, y: number}} dimension
* @returns {{x: number, y: number}}
*/
let adjustPos = (position, dimension) => mapObject(roundPos(position), (v, k) => Math.max(1, Math.min(dimension[k], v)) );
/**
* like Array.map() for objects
* -> callback f is called for each property
* @see https://stackoverflow.com/a/38829074/4329969
* @param o
* @param f
* @returns {Object}
*/
let mapObject = (o, f) => Object.assign(...Object.entries(o).map(([k, v]) => ({[k]: f(v, k) })));
return {
initScrollbar: initScrollbar,
scrollToPosition: scrollToPosition,
scrollToCenter: scrollToCenter
};
});