- fixed some JS _race condition_ render issues

This commit is contained in:
Mark Friedrich
2018-07-15 16:07:32 +02:00
parent 252c995fe6
commit b047e9d951
10 changed files with 362 additions and 288 deletions

View File

@@ -1223,81 +1223,6 @@ define([
return connection;
};
/**
* make all systems appear visual on the map with its connections
* @param show
* @param callback
*/
$.fn.visualizeMap = function(show, callback){
let mapElement = $(this);
// start map update counter -> prevent map updates during animations
mapElement.getMapOverlay('timer').startMapUpdateCounter();
let systemElements = mapElement.find('.' + config.systemClass);
let endpointElements = mapElement.find('.jsplumb-endpoint:visible');
let connectorElements = mapElement.find('.jsplumb-connector:visible');
let overlayElements = mapElement.find('.jsplumb-overlay:visible, .tooltip');
let hideElements = (elements) => {
if(elements.length > 0){
// disable transition for next opacity change
elements.addClass('pf-notransition');
// hide elements
elements.css('opacity', 0);
// Trigger a reflow, flushing the CSS changes
// -> http://stackoverflow.com/questions/11131875/what-is-the-cleanest-way-to-disable-css-transition-effects-temporarily
elements[0].offsetHeight; // jshint ignore:line
elements.removeClass('pf-notransition');
}
return elements;
};
let mapElements = systemElements.add(endpointElements).add(connectorElements);
// show nice animation
if(show === 'show'){
hideElements(systemElements);
hideElements(endpointElements);
hideElements(connectorElements);
hideElements(overlayElements);
overlayElements.velocity('transition.fadeIn', {
duration: 60,
display: 'auto'
});
mapElements.velocity({
translateY: [ 0, -20],
opacity: [ 1, 0 ]
}, {
duration: 150,
easing: 'easeOut',
complete: function(){
callback();
}
});
}else if(show === 'hide'){
overlayElements.velocity('transition.fadeOut', {
duration: 60,
display: 'auto'
});
mapElements.velocity({
translateY: [ -20, 0 ],
opacity: [ 0, 1 ]
}, {
duration: 150,
easing: 'easeOut',
complete: function(){
callback();
}
});
}
};
/**
* mark a system as source
* @param map
@@ -3315,11 +3240,6 @@ define([
*/
let initMapOptions = (mapConfig, options) => {
/**
* init map options promise
* @param resolve
* @param reject
*/
let initMapOptionsExecutor = (resolve, reject) => {
let payload = {
action: 'initMapOptions',
@@ -3329,63 +3249,18 @@ define([
};
if(options.showAnimation){
/**
* callback after visualizeMap is done
* @param mapName
* @param mapContainer
*/
let switchTabCallback = (mapContainer, mapConfig) => {
Util.showNotify({title: 'Map initialized', text: mapConfig.name + ' - loaded', type: 'success'});
let mapWrapper = mapContainer.parents('.' + config.mapWrapperClass);
// auto scroll map to previous position -----------------------------------------------------------
let promiseStore = MapUtil.getLocaleData('map', mapContainer.data('id') );
promiseStore.then(data => {
// This code runs once the value has been loaded from offline storage
if(data && data.scrollOffset){
mapWrapper.scrollToPosition([data.scrollOffset.y, data.scrollOffset.x]);
}
});
// update main menu options based on the active map -----------------------------------------------
$(document).trigger('pf:updateMenuOptions', {
mapConfig: mapConfig
});
// init magnetizer --------------------------------------------------------------------------------
mapContainer.triggerMenuEvent('MapOption', {
option: 'mapMagnetizer',
toggle: false
});
// init grid snap ---------------------------------------------------------------------------------
mapContainer.triggerMenuEvent('MapOption', {
option: 'mapSnapToGrid',
toggle: false
});
// init endpoint overlay --------------------------------------------------------------------------
mapContainer.triggerMenuEvent('MapOption', {
option: 'mapEndpoint',
toggle: false
});
// init compact system UI --------------------------------------------------------------------------
mapContainer.triggerMenuEvent('MapOption', {
option: 'mapCompact',
toggle: false
});
};
// show nice visualization effect ---------------------------------------------------------------------
let mapContainer = $(mapConfig.map.getContainer());
mapContainer.visualizeMap('show', function(){
switchTabCallback(mapContainer, mapConfig.config);
});
let mapElement = $(mapConfig.map.getContainer());
MapUtil.setMapDefaultOptions(mapElement, mapConfig.config)
.then(payload => MapUtil.visualizeMap(mapElement, 'show'))
.then(payload => MapUtil.scrollToDefaultPosition(mapElement))
.then(payload => {
Util.showNotify({title: 'Map initialized', text: mapConfig.config.name + ' - loaded', type: 'success'});
})
.then(() => resolve(payload));
}else{
// nothing to do here...
resolve(payload);
}
resolve(payload);
};
return new Promise(initMapOptionsExecutor);

View File

@@ -19,6 +19,8 @@ define([
mapLocalStoragePrefix: 'map_', // prefix for map data local storage key
mapTabContentClass: 'pf-map-tab-content', // Tab-Content element (parent element)
mapWrapperClass: 'pf-map-wrapper', // wrapper div (scrollable)
mapClass: 'pf-map', // class for all maps
mapGridClass: 'pf-grid-small', // class for map grid snapping
mapCompactClass: 'pf-compact', // class for map compact system UI
@@ -961,6 +963,167 @@ define([
}
};
/**
* show map animations when a new map gets visual
* @param mapElement
* @param show
* @returns {Promise<any>}
*/
let visualizeMap = (mapElement, show) => {
let visualizeMapExecutor = (resolve, reject) => {
// start map update counter -> prevent map updates during animations
mapElement.getMapOverlay('timer').startMapUpdateCounter();
let systemElements = mapElement.find('.' + config.systemClass);
let endpointElements = mapElement.find('.jsplumb-endpoint:visible');
let connectorElements = mapElement.find('.jsplumb-connector:visible');
let overlayElements = mapElement.find('.jsplumb-overlay:visible, .tooltip');
let hideElements = (elements) => {
if(elements.length > 0){
// disable transition for next opacity change
elements.addClass('pf-notransition');
// hide elements
elements.css('opacity', 0);
// Trigger a reflow, flushing the CSS changes
// -> http://stackoverflow.com/questions/11131875/what-is-the-cleanest-way-to-disable-css-transition-effects-temporarily
elements[0].offsetHeight; // jshint ignore:line
elements.removeClass('pf-notransition');
}
return elements;
};
let mapElements = systemElements.add(endpointElements).add(connectorElements);
// show nice animation
if(show === 'show'){
hideElements(systemElements);
hideElements(endpointElements);
hideElements(connectorElements);
hideElements(overlayElements);
overlayElements.velocity('transition.fadeIn', {
duration: 60,
display: 'auto'
});
mapElements.velocity({
translateY: [ 0, -20],
opacity: [ 1, 0 ]
}, {
duration: 150,
easing: 'easeOut',
complete: function(){
resolve({
action: 'visualizeMap',
data: false
});
}
});
}else if(show === 'hide'){
overlayElements.velocity('transition.fadeOut', {
duration: 60,
display: 'auto'
});
mapElements.velocity({
translateY: [ -20, 0 ],
opacity: [ 0, 1 ]
}, {
duration: 150,
easing: 'easeOut',
complete: function(){
resolve({
action: 'visualizeMap',
data: false
});
}
});
}
};
return new Promise(visualizeMapExecutor);
};
/**
* set default map Options (
* -> HINT: This function triggers Events! Promise is resolved before trigger completed
* @param mapElement
* @param mapConfig
* @returns {Promise<any>}
*/
let setMapDefaultOptions = (mapElement, mapConfig) => {
let setMapDefaultOptionsExecutor = (resolve, reject) => {
// update main menu options based on the active map -----------------------------------------------
$(document).trigger('pf:updateMenuOptions', {
mapConfig: mapConfig
});
// init compact system layout ---------------------------------------------------------------------
mapElement.triggerMenuEvent('MapOption', {
option: 'mapCompact',
toggle: false
});
// init magnetizer --------------------------------------------------------------------------------
mapElement.triggerMenuEvent('MapOption', {
option: 'mapMagnetizer',
toggle: false
});
// init grid snap ---------------------------------------------------------------------------------
mapElement.triggerMenuEvent('MapOption', {
option: 'mapSnapToGrid',
toggle: false
});
// init endpoint overlay --------------------------------------------------------------------------
mapElement.triggerMenuEvent('MapOption', {
option: 'mapEndpoint',
toggle: false
});
resolve({
action: 'setMapDefaultOptions',
data: false
});
};
return new Promise(setMapDefaultOptionsExecutor);
};
/**
* scroll map to default (stored) x/y coordinates
* @param mapElement
* @returns {Promise<any>}
*/
let scrollToDefaultPosition = (mapElement) => {
let scrollToDefaultPositionExecutor = (resolve, reject) => {
let mapWrapper = mapElement.parents('.' + config.mapWrapperClass);
// auto scroll map to previous stored position
let promiseStore = getLocaleData('map', mapElement.data('id'));
promiseStore.then(data => {
// This code runs once the value has been loaded from offline storage
if(data && data.scrollOffset){
mapWrapper.scrollToPosition([data.scrollOffset.y, data.scrollOffset.x]);
}
resolve({
action: 'scrollToDefaultPosition',
data: false
});
});
};
return new Promise(scrollToDefaultPositionExecutor);
};
/**
* delete local map configuration by key (IndexedDB)
* @param type
@@ -1440,6 +1603,9 @@ define([
getLocaleData: getLocaleData,
storeLocalData: storeLocalData,
deleteLocalData: deleteLocalData,
visualizeMap: visualizeMap,
setMapDefaultOptions: setMapDefaultOptions,
scrollToDefaultPosition: scrollToDefaultPosition,
getSystemId: getSystemId,
checkRight: checkRight,
getMapDeeplinkUrl: getMapDeeplinkUrl,

View File

@@ -257,12 +257,12 @@ define([
onGet: (MsgWorkerMessage) => {
switch(MsgWorkerMessage.task()){
case 'mapUpdate':
Util.updateCurrentMapData( MsgWorkerMessage.data() );
Util.updateCurrentMapData(MsgWorkerMessage.data());
ModuleMap.updateMapModule(mapModule);
break;
case 'mapAccess':
case 'mapDeleted':
Util.deleteCurrentMapData( MsgWorkerMessage.data() );
Util.deleteCurrentMapData(MsgWorkerMessage.data());
ModuleMap.updateMapModule(mapModule);
break;
case 'mapSubscriptions':

View File

@@ -682,7 +682,7 @@ define([
mapElement.data('frozen', true);
// hide current map with animation
mapElement.visualizeMap('hide', function(){
MapUtil.visualizeMap(mapElement, 'hide').then(payload => {
// un-block map tabs
mapTabChangeBlocked = switchTabCallback(mapElement, tabLinkElement);
});

View File

@@ -455,11 +455,7 @@ define([
* @param event
* @param data
*/
$.fn.triggerMenuEvent = function(event, data){
if(data === undefined){
data = {};
}
$.fn.triggerMenuEvent = function(event, data = {}){
$(this).trigger('pf:menu' + event, [data]);
};

View File

@@ -1223,81 +1223,6 @@ define([
return connection;
};
/**
* make all systems appear visual on the map with its connections
* @param show
* @param callback
*/
$.fn.visualizeMap = function(show, callback){
let mapElement = $(this);
// start map update counter -> prevent map updates during animations
mapElement.getMapOverlay('timer').startMapUpdateCounter();
let systemElements = mapElement.find('.' + config.systemClass);
let endpointElements = mapElement.find('.jsplumb-endpoint:visible');
let connectorElements = mapElement.find('.jsplumb-connector:visible');
let overlayElements = mapElement.find('.jsplumb-overlay:visible, .tooltip');
let hideElements = (elements) => {
if(elements.length > 0){
// disable transition for next opacity change
elements.addClass('pf-notransition');
// hide elements
elements.css('opacity', 0);
// Trigger a reflow, flushing the CSS changes
// -> http://stackoverflow.com/questions/11131875/what-is-the-cleanest-way-to-disable-css-transition-effects-temporarily
elements[0].offsetHeight; // jshint ignore:line
elements.removeClass('pf-notransition');
}
return elements;
};
let mapElements = systemElements.add(endpointElements).add(connectorElements);
// show nice animation
if(show === 'show'){
hideElements(systemElements);
hideElements(endpointElements);
hideElements(connectorElements);
hideElements(overlayElements);
overlayElements.velocity('transition.fadeIn', {
duration: 60,
display: 'auto'
});
mapElements.velocity({
translateY: [ 0, -20],
opacity: [ 1, 0 ]
}, {
duration: 150,
easing: 'easeOut',
complete: function(){
callback();
}
});
}else if(show === 'hide'){
overlayElements.velocity('transition.fadeOut', {
duration: 60,
display: 'auto'
});
mapElements.velocity({
translateY: [ -20, 0 ],
opacity: [ 0, 1 ]
}, {
duration: 150,
easing: 'easeOut',
complete: function(){
callback();
}
});
}
};
/**
* mark a system as source
* @param map
@@ -3315,11 +3240,6 @@ define([
*/
let initMapOptions = (mapConfig, options) => {
/**
* init map options promise
* @param resolve
* @param reject
*/
let initMapOptionsExecutor = (resolve, reject) => {
let payload = {
action: 'initMapOptions',
@@ -3329,63 +3249,18 @@ define([
};
if(options.showAnimation){
/**
* callback after visualizeMap is done
* @param mapName
* @param mapContainer
*/
let switchTabCallback = (mapContainer, mapConfig) => {
Util.showNotify({title: 'Map initialized', text: mapConfig.name + ' - loaded', type: 'success'});
let mapWrapper = mapContainer.parents('.' + config.mapWrapperClass);
// auto scroll map to previous position -----------------------------------------------------------
let promiseStore = MapUtil.getLocaleData('map', mapContainer.data('id') );
promiseStore.then(data => {
// This code runs once the value has been loaded from offline storage
if(data && data.scrollOffset){
mapWrapper.scrollToPosition([data.scrollOffset.y, data.scrollOffset.x]);
}
});
// update main menu options based on the active map -----------------------------------------------
$(document).trigger('pf:updateMenuOptions', {
mapConfig: mapConfig
});
// init magnetizer --------------------------------------------------------------------------------
mapContainer.triggerMenuEvent('MapOption', {
option: 'mapMagnetizer',
toggle: false
});
// init grid snap ---------------------------------------------------------------------------------
mapContainer.triggerMenuEvent('MapOption', {
option: 'mapSnapToGrid',
toggle: false
});
// init endpoint overlay --------------------------------------------------------------------------
mapContainer.triggerMenuEvent('MapOption', {
option: 'mapEndpoint',
toggle: false
});
// init compact system UI --------------------------------------------------------------------------
mapContainer.triggerMenuEvent('MapOption', {
option: 'mapCompact',
toggle: false
});
};
// show nice visualization effect ---------------------------------------------------------------------
let mapContainer = $(mapConfig.map.getContainer());
mapContainer.visualizeMap('show', function(){
switchTabCallback(mapContainer, mapConfig.config);
});
let mapElement = $(mapConfig.map.getContainer());
MapUtil.setMapDefaultOptions(mapElement, mapConfig.config)
.then(payload => MapUtil.visualizeMap(mapElement, 'show'))
.then(payload => MapUtil.scrollToDefaultPosition(mapElement))
.then(payload => {
Util.showNotify({title: 'Map initialized', text: mapConfig.config.name + ' - loaded', type: 'success'});
})
.then(() => resolve(payload));
}else{
// nothing to do here...
resolve(payload);
}
resolve(payload);
};
return new Promise(initMapOptionsExecutor);

View File

@@ -19,6 +19,8 @@ define([
mapLocalStoragePrefix: 'map_', // prefix for map data local storage key
mapTabContentClass: 'pf-map-tab-content', // Tab-Content element (parent element)
mapWrapperClass: 'pf-map-wrapper', // wrapper div (scrollable)
mapClass: 'pf-map', // class for all maps
mapGridClass: 'pf-grid-small', // class for map grid snapping
mapCompactClass: 'pf-compact', // class for map compact system UI
@@ -961,6 +963,167 @@ define([
}
};
/**
* show map animations when a new map gets visual
* @param mapElement
* @param show
* @returns {Promise<any>}
*/
let visualizeMap = (mapElement, show) => {
let visualizeMapExecutor = (resolve, reject) => {
// start map update counter -> prevent map updates during animations
mapElement.getMapOverlay('timer').startMapUpdateCounter();
let systemElements = mapElement.find('.' + config.systemClass);
let endpointElements = mapElement.find('.jsplumb-endpoint:visible');
let connectorElements = mapElement.find('.jsplumb-connector:visible');
let overlayElements = mapElement.find('.jsplumb-overlay:visible, .tooltip');
let hideElements = (elements) => {
if(elements.length > 0){
// disable transition for next opacity change
elements.addClass('pf-notransition');
// hide elements
elements.css('opacity', 0);
// Trigger a reflow, flushing the CSS changes
// -> http://stackoverflow.com/questions/11131875/what-is-the-cleanest-way-to-disable-css-transition-effects-temporarily
elements[0].offsetHeight; // jshint ignore:line
elements.removeClass('pf-notransition');
}
return elements;
};
let mapElements = systemElements.add(endpointElements).add(connectorElements);
// show nice animation
if(show === 'show'){
hideElements(systemElements);
hideElements(endpointElements);
hideElements(connectorElements);
hideElements(overlayElements);
overlayElements.velocity('transition.fadeIn', {
duration: 60,
display: 'auto'
});
mapElements.velocity({
translateY: [ 0, -20],
opacity: [ 1, 0 ]
}, {
duration: 150,
easing: 'easeOut',
complete: function(){
resolve({
action: 'visualizeMap',
data: false
});
}
});
}else if(show === 'hide'){
overlayElements.velocity('transition.fadeOut', {
duration: 60,
display: 'auto'
});
mapElements.velocity({
translateY: [ -20, 0 ],
opacity: [ 0, 1 ]
}, {
duration: 150,
easing: 'easeOut',
complete: function(){
resolve({
action: 'visualizeMap',
data: false
});
}
});
}
};
return new Promise(visualizeMapExecutor);
};
/**
* set default map Options (
* -> HINT: This function triggers Events! Promise is resolved before trigger completed
* @param mapElement
* @param mapConfig
* @returns {Promise<any>}
*/
let setMapDefaultOptions = (mapElement, mapConfig) => {
let setMapDefaultOptionsExecutor = (resolve, reject) => {
// update main menu options based on the active map -----------------------------------------------
$(document).trigger('pf:updateMenuOptions', {
mapConfig: mapConfig
});
// init compact system layout ---------------------------------------------------------------------
mapElement.triggerMenuEvent('MapOption', {
option: 'mapCompact',
toggle: false
});
// init magnetizer --------------------------------------------------------------------------------
mapElement.triggerMenuEvent('MapOption', {
option: 'mapMagnetizer',
toggle: false
});
// init grid snap ---------------------------------------------------------------------------------
mapElement.triggerMenuEvent('MapOption', {
option: 'mapSnapToGrid',
toggle: false
});
// init endpoint overlay --------------------------------------------------------------------------
mapElement.triggerMenuEvent('MapOption', {
option: 'mapEndpoint',
toggle: false
});
resolve({
action: 'setMapDefaultOptions',
data: false
});
};
return new Promise(setMapDefaultOptionsExecutor);
};
/**
* scroll map to default (stored) x/y coordinates
* @param mapElement
* @returns {Promise<any>}
*/
let scrollToDefaultPosition = (mapElement) => {
let scrollToDefaultPositionExecutor = (resolve, reject) => {
let mapWrapper = mapElement.parents('.' + config.mapWrapperClass);
// auto scroll map to previous stored position
let promiseStore = getLocaleData('map', mapElement.data('id'));
promiseStore.then(data => {
// This code runs once the value has been loaded from offline storage
if(data && data.scrollOffset){
mapWrapper.scrollToPosition([data.scrollOffset.y, data.scrollOffset.x]);
}
resolve({
action: 'scrollToDefaultPosition',
data: false
});
});
};
return new Promise(scrollToDefaultPositionExecutor);
};
/**
* delete local map configuration by key (IndexedDB)
* @param type
@@ -1440,6 +1603,9 @@ define([
getLocaleData: getLocaleData,
storeLocalData: storeLocalData,
deleteLocalData: deleteLocalData,
visualizeMap: visualizeMap,
setMapDefaultOptions: setMapDefaultOptions,
scrollToDefaultPosition: scrollToDefaultPosition,
getSystemId: getSystemId,
checkRight: checkRight,
getMapDeeplinkUrl: getMapDeeplinkUrl,

View File

@@ -257,12 +257,12 @@ define([
onGet: (MsgWorkerMessage) => {
switch(MsgWorkerMessage.task()){
case 'mapUpdate':
Util.updateCurrentMapData( MsgWorkerMessage.data() );
Util.updateCurrentMapData(MsgWorkerMessage.data());
ModuleMap.updateMapModule(mapModule);
break;
case 'mapAccess':
case 'mapDeleted':
Util.deleteCurrentMapData( MsgWorkerMessage.data() );
Util.deleteCurrentMapData(MsgWorkerMessage.data());
ModuleMap.updateMapModule(mapModule);
break;
case 'mapSubscriptions':

View File

@@ -682,7 +682,7 @@ define([
mapElement.data('frozen', true);
// hide current map with animation
mapElement.visualizeMap('hide', function(){
MapUtil.visualizeMap(mapElement, 'hide').then(payload => {
// un-block map tabs
mapTabChangeBlocked = switchTabCallback(mapElement, tabLinkElement);
});

View File

@@ -455,11 +455,7 @@ define([
* @param event
* @param data
*/
$.fn.triggerMenuEvent = function(event, data){
if(data === undefined){
data = {};
}
$.fn.triggerMenuEvent = function(event, data = {}){
$(this).trigger('pf:menu' + event, [data]);
};