diff --git a/ChangeLog b/ChangeLog index 3c73de676..754b18940 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ Frontend: Worldmap: * textbox scaling according to zoom (scale_to_max_zoom option) (issue #255) + * Feature: screen-fixed objects 1.9.20 Core: diff --git a/docs/en_US/worldmap.html b/docs/en_US/worldmap.html index 7370f67c4..c4765cda4 100644 --- a/docs/en_US/worldmap.html +++ b/docs/en_US/worldmap.html @@ -95,5 +95,28 @@

Objects on worldmap and zoom

scale_to_max_zoomNoScale the object size down to 50% for every zoom level below max_zoom. Only applicable to textboxes. + +

Screen-fixed objects

+ + Screen-fixed objects do not move when a map is dragged or zoomed. Unlike any worldmap objects, those are placed to screen by pixels rather than geographical coordinates. + + + + + + + + +
ParameterDefaultDescription
worldmap_screenfixed_objects_from_mapnoneName of other regular map to load screen-fixed objects from.
+ + To use the feature, create two maps: +
    +
  1. This worldmap
  2. +
  3. Another regular map
  4. +
+ On this worldmap (1), set worldmap_screenfixed_objects_from_map=name_of_another_regular_map. Objects from regular map (2) are now visible on this worldmap (1) and are always fixed to the same spot on the screen. + +You may also want to set show_in_lists=0 on the referred regular map. + diff --git a/share/frontend/nagvis-js/js/ElementLine.js b/share/frontend/nagvis-js/js/ElementLine.js index 0bfdcf7f1..f4b2f0752 100644 --- a/share/frontend/nagvis-js/js/ElementLine.js +++ b/share/frontend/nagvis-js/js/ElementLine.js @@ -293,7 +293,14 @@ var ElementLine = Element.extend({ // the user moves the object, this dom node must not be re-created, because this // would remove all event handlers if (!this.obj.trigger_obj) { - var oLink = document.createElement('a'); + if (this.obj.conf.url) { + var oLink = document.createElement('a'); + oLink.href = this.obj.conf.url; + oLink.target = this.obj.conf.url_target; + } else { + var oLink = document.createElement('div'); + oLink.style.cursor = 'pointer'; + } oLink.setAttribute('id', this.obj.conf.object_id+'-linelink'); oLink.className = 'linelink'; this.obj.trigger_obj = oLink; @@ -302,12 +309,6 @@ var ElementLine = Element.extend({ this.clearActionContainer(); } this.dom_obj.appendChild(oLink); - if (this.obj.conf.url) { - oLink.href = this.obj.conf.url; - oLink.target = this.obj.conf.url_target; - } else { - oLink.href = 'javascript:void(0)'; - } }, clearActionContainer: function() { @@ -619,13 +620,13 @@ var ElementLine = Element.extend({ this.link_area.style.left = (x-5) + 'px'; this.link_area.style.top = (y-5) + 'px'; - if (usesSource('worldmap')) + if (usesSource('worldmap') && this.obj.marker) this.obj.marker._bringToFront(); } else { remove_class(this.canvas, 'active'); this.link_area.style.display = 'none'; - if (usesSource('worldmap')) + if (usesSource('worldmap') && this.obj.marker) this.obj.marker._resetZIndex(); } }, diff --git a/share/frontend/nagvis-js/js/ViewMap.js b/share/frontend/nagvis-js/js/ViewMap.js index c2287d9d5..a7db0cba5 100644 --- a/share/frontend/nagvis-js/js/ViewMap.js +++ b/share/frontend/nagvis-js/js/ViewMap.js @@ -164,6 +164,11 @@ var ViewMap = View.extend({ }, addObject: function(attrs) { + let obj = this.constructObject(attrs); + this.objects[obj.conf.object_id] = obj; + }, + + constructObject: function(attrs) { var obj; switch (attrs.type) { case 'host': @@ -204,13 +209,12 @@ var ViewMap = View.extend({ return; break; } - + // Save the number of unlocked objects if (!obj.bIsLocked) this.updateNumUnlocked(1); - - // Put object to map objects array - this.objects[obj.conf.object_id] = obj; + + return obj; }, erase: function() { @@ -225,7 +229,7 @@ var ViewMap = View.extend({ // FIXME: Are all these steps needed here? obj.update(); obj.render(); - + // add eventhandling when enabled via event_on_load option if (isset(oViewProperties.event_on_load) && oViewProperties.event_on_load == 1 && obj.has_state && obj.hasProblematicState()) { @@ -247,7 +251,7 @@ var ViewMap = View.extend({ this.dom_obj.appendChild(obj.dom_obj); }, - // Removes the given objects dom_obj from the maps dom_obj + // Removes the given objects dom_obj from the maps dom_obj eraseObject: function(obj) { this.dom_obj.removeChild(obj.dom_obj); }, @@ -255,13 +259,13 @@ var ViewMap = View.extend({ // Does initial rendering of map objects initializeObjects: function(aMapObjectConf) { eventlog("worker", "debug", "initializeObjects: Start setting map objects"); - + // Don't loop the first object - that is the summary of the current map this.sum_obj = new NagVisMap(aMapObjectConf[0]); - + for (var i = 1, len = aMapObjectConf.length; i < len; i++) this.addObject(aMapObjectConf[i]); - + // First parse the objects on the map // Then store the object position dependencies. // Before both can be done all objects need to be added diff --git a/share/frontend/nagvis-js/js/ViewWorldmap.js b/share/frontend/nagvis-js/js/ViewWorldmap.js index f095ea79d..2256b2940 100644 --- a/share/frontend/nagvis-js/js/ViewWorldmap.js +++ b/share/frontend/nagvis-js/js/ViewWorldmap.js @@ -22,6 +22,8 @@ *****************************************************************************/ var ViewWorldmap = ViewMap.extend({ + screenFixedObjects: [], + constructor: function(id) { this.base(id); }, @@ -111,6 +113,45 @@ var ViewWorldmap = ViewMap.extend({ let ltp = document.getElementsByClassName('leaflet-tile-pane'); if (ltp && saturate_percentage !== '') ltp[0].style.filter = "saturate("+saturate_percentage+"%)"; + + let loadScreenfixedObjectsFrom = getViewParam('worldmap_screenfixed_objects_from_map'); + if (loadScreenfixedObjectsFrom) { + call_ajax(oGeneralProperties.path_server + '?mod=Map&act=getMapObjects&show=' + loadScreenfixedObjectsFrom, { + response_handler : this.initializescreenFixedObjects.bind(this), + }); + } + + }, + + initializescreenFixedObjects: function(aMapObjectConf) { + // Counterfeit `ViewMap` instance instead of `ViewWorldmap` so that screen-fixed object's DOM elements get rendered out of Leaflet map + let g_view_tmp = g_view + g_view = new ViewMap(g_view_tmp.id) + g_view.init(); + + for (var i = 1, len = aMapObjectConf.length; i < len; i++) { + this.addScreenfixedObject(aMapObjectConf[i]); + } + + for (var i in this.screenFixedObjects) + this.renderScreenfixedObject(i); + + // restore original `ViewWorldmap` instance + g_view = g_view_tmp + }, + + + addScreenfixedObject: function(attrs) { + attrs.context_menu = '0'; // no right-click context menu on screenfixed objects + attrs.z = Number(attrs.z) + 1000; // always on top of leaflet panes + let obj = this.constructObject(attrs); + this.screenFixedObjects[obj.conf.object_id] = obj; + }, + + renderScreenfixedObject: function(object_id) { + var obj = this.screenFixedObjects[object_id]; + obj.update(); + obj.render(); }, handleMoveStart: function(lEvent) { diff --git a/share/frontend/nagvis-js/js/frontend.js b/share/frontend/nagvis-js/js/frontend.js index 7478fd8d6..75e1cc258 100644 --- a/share/frontend/nagvis-js/js/frontend.js +++ b/share/frontend/nagvis-js/js/frontend.js @@ -124,7 +124,7 @@ function showFrontendDialog(sUrl, sTitle, sWidth) { response.url = sUrl; if(typeof response !== 'undefined' && typeof response.code !== 'undefined') { - let width = data.sWidth || 450; + let width = data.sWidth || 650; if (response.object_type === 'textbox') width = 800 popupWindow(data.title, response, width); } diff --git a/share/server/core/classes/GlobalCore.php b/share/server/core/classes/GlobalCore.php index 2f7b79df9..ad6c9a17f 100644 --- a/share/server/core/classes/GlobalCore.php +++ b/share/server/core/classes/GlobalCore.php @@ -453,7 +453,7 @@ public function getListMaps() { } catch(NagVisException $e) { continue; // skip e.g. not read config files } - + if($MAPCFG->getValue(0, 'show_in_lists') == 1) $list[$mapName] = $MAPCFG->getAlias(); } @@ -461,6 +461,27 @@ public function getListMaps() { return array_keys($list); } + public function getListRegularMaps() { + $list = array(); + $maps = $this->getPermittedMaps(); + foreach ($maps AS $mapName) { + $MAPCFG = new GlobalMapCfg($mapName); + try { + $MAPCFG->readMapConfig(ONLY_GLOBAL); + } catch(MapCfgInvalid $e) { + continue; // skip configs with broken global sections + } catch(NagVisException $e) { + continue; // skip e.g. not read config files + } + + // maps with no 'sources=' in 'define global {}' section are regular + if($MAPCFG->getValue(0, 'sources') == []) + $list[$mapName] = $MAPCFG->getAlias(); + } + natcasesort($list); + return array_keys($list); + } + /** * Reads all map images in map path * diff --git a/share/server/core/mapcfg/default.php b/share/server/core/mapcfg/default.php index 8ccc38a58..e52c36ec9 100644 --- a/share/server/core/mapcfg/default.php +++ b/share/server/core/mapcfg/default.php @@ -27,6 +27,11 @@ function listMapNames() { return $list; } +function listRegularMapNames() { + global $CORE; + return $CORE->getListRegularMaps(); +} + function listMapImages() { global $CORE; $options = $CORE->getAvailableBackgroundImages(); diff --git a/share/server/core/sources/worldmap.php b/share/server/core/sources/worldmap.php index 509660a2d..84a7ab9d3 100644 --- a/share/server/core/sources/worldmap.php +++ b/share/server/core/sources/worldmap.php @@ -37,6 +37,13 @@ class WorldmapError extends MapSourceError {} 'default' => '', 'match' => MATCH_INTEGER_EMPTY, ), + 'worldmap_screenfixed_objects_from_map' => array( + 'must' => 0, + 'default' => '', + 'match' => MATCH_MAP_NAME_EMPTY, + 'field_type' => 'dropdown', + 'list' => 'listRegularMapNames', + ), /*** OBJECT OPTIONS ***/ 'min_zoom' => array( @@ -59,6 +66,7 @@ class WorldmapError extends MapSourceError {} 'worldmap_center' => null, 'worldmap_zoom' => null, 'worldmap_tiles_saturate' => null, + 'worldmap_screenfixed_objects_from_map' => null, ), ), );