From d94544d9989554bc155a6867df01bca507df7c27 Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Mon, 3 Aug 2020 13:16:53 +0100 Subject: [PATCH] Add minimap capability --- CHANGELOG.md | 1 + README.md | 17 +++++++++++++++++ examples/Add Minimap.json | 1 + package.json | 4 ++-- worldmap.html | 24 ++++++++++++------------ worldmap.js | 2 +- worldmap/index.html | 2 ++ worldmap/leaflet/Control.MiniMap.min.css | 1 + worldmap/leaflet/Control.MiniMap.min.js | 1 + worldmap/leaflet/images/toggle.svg | 1 + worldmap/worldmap.js | 13 +++++++++++++ 11 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 examples/Add Minimap.json create mode 100644 worldmap/leaflet/Control.MiniMap.min.css create mode 100644 worldmap/leaflet/Control.MiniMap.min.js create mode 100644 worldmap/leaflet/images/toggle.svg diff --git a/CHANGELOG.md b/CHANGELOG.md index bc81923..f319317 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### Change Log for Node-RED Worldmap + - v2.5.0 - Add minimap capability. - v2.4.2 - Fix editing injected shapes. - v2.4.1 - Add convex-hull node for grouping objects. - v2.3.16 - Add heading to default addMarker, allow custom http icon size. diff --git a/README.md b/README.md index 0ba87d2..7f07831 100644 --- a/README.md +++ b/README.md @@ -445,6 +445,23 @@ may let you markers be more visible. (see overlay example below). "opt":{ "maxZoom":19, "attribution":"© OpenStreetMap" } }; +#### To add a minimap + +A minimap overview can be added by sending a suitable command. The "minimap" property +must specify the name of an existing base layer to use. The "opt" property can contain +valid options from the [minimap library options](https://github.com/Norkart/Leaflet-MiniMap#available-options). + + msg.payload.command.map = { + minimap: "OSM", + opt: { + centerFixed: [51.05, -1.35], + toggleDisplay: true + } + } + }; + +Set `msg.payload.command.map.minimap = false;` to remove the minimap. + #### To remove base or overlay layers To remove several layers, either base layers or overlays, you can pass an array of names as follows. diff --git a/examples/Add Minimap.json b/examples/Add Minimap.json new file mode 100644 index 0000000..d618429 --- /dev/null +++ b/examples/Add Minimap.json @@ -0,0 +1 @@ +[{"id":"fd654fbf.7e7db","type":"worldmap","z":"846d7832.3348c8","name":"","lat":"","lon":"","zoom":"14","layer":"","cluster":"","maxage":"","usermenu":"show","layers":"show","panit":"false","panlock":"false","zoomlock":"false","hiderightclick":"false","coords":"none","showgrid":"false","path":"/worldmap","x":500,"y":540,"wires":[]},{"id":"3a9f5292.247a0e","type":"inject","z":"846d7832.3348c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":130,"y":540,"wires":[["e5161e3c.df6a1"]]},{"id":"e5161e3c.df6a1","type":"function","z":"846d7832.3348c8","name":"Add minimap","func":"msg.payload = {\n command: {\n map: {\n minimap: \"OSM\",\n opt: {\n \t\t\tcenterFixed: [51.05, -1.35],\n \t\t\ttoggleDisplay: true\n \t\t}\n }\n }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":310,"y":540,"wires":[["fd654fbf.7e7db"]]},{"id":"ebe0f256.5a1b7","type":"inject","z":"846d7832.3348c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":130,"y":580,"wires":[["a7e940a5.a24b6"]]},{"id":"a7e940a5.a24b6","type":"function","z":"846d7832.3348c8","name":"Remove minimap","func":"msg.payload = {\n command: {\n map: {\n minimap: false\n }\n }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":330,"y":580,"wires":[["fd654fbf.7e7db"]]}] \ No newline at end of file diff --git a/package.json b/package.json index 20ac75b..2528149 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "node-red-contrib-web-worldmap", - "version": "2.4.2", + "version": "2.5.0", "description": "A Node-RED node to provide a web page of a world map for plotting things on.", "dependencies": { "cgi": "0.3.1", "compression": "^1.7.4", "express": "^4.16.4", - "sockjs": "~0.3.20" + "sockjs": "~0.3.21" }, "repository": { "type": "git", diff --git a/worldmap.html b/worldmap.html index 05d20b9..823982c 100644 --- a/worldmap.html +++ b/worldmap.html @@ -54,36 +54,36 @@
- Layer menu -
- Lock zoom -
- Right click - @@ -201,36 +201,36 @@ then by default ⌘⇧m - ctrl-shift-m will load the m
- Layer menu -
- Lock zoom -
- Right click - diff --git a/worldmap.js b/worldmap.js index d041559..f70a3ee 100644 --- a/worldmap.js +++ b/worldmap.js @@ -426,7 +426,7 @@ module.exports = function(RED) { if (leafletHull.length > 1) { // if (leafletHull.length === 2) { newmsg.payload.line = leafletHull; } // else { - newmsg.payload.area = leafletHull; + newmsg.payload.area = leafletHull; // } newmsg.payload.name = newmsg.payload[node.prop]; newmsg.payload.clickable = true; diff --git a/worldmap/index.html b/worldmap/index.html index 760d5b8..a62625f 100644 --- a/worldmap/index.html +++ b/worldmap/index.html @@ -36,6 +36,7 @@ + @@ -60,6 +61,7 @@ + diff --git a/worldmap/leaflet/Control.MiniMap.min.css b/worldmap/leaflet/Control.MiniMap.min.css new file mode 100644 index 0000000..2886943 --- /dev/null +++ b/worldmap/leaflet/Control.MiniMap.min.css @@ -0,0 +1 @@ +.leaflet-control-minimap{border:rgba(255,255,255,1) solid;box-shadow:0 1px 5px rgba(0,0,0,.65);border-radius:3px;background:#f8f8f9;transition:all .6s}.leaflet-control-minimap a{background-color:rgba(255,255,255,1);background-repeat:no-repeat;z-index:99999;transition:all .6s}.leaflet-control-minimap a.minimized-bottomright{-webkit-transform:rotate(180deg);transform:rotate(180deg);border-radius:0}.leaflet-control-minimap a.minimized-topleft{-webkit-transform:rotate(0deg);transform:rotate(0deg);border-radius:0}.leaflet-control-minimap a.minimized-bottomleft{-webkit-transform:rotate(270deg);transform:rotate(270deg);border-radius:0}.leaflet-control-minimap a.minimized-topright{-webkit-transform:rotate(90deg);transform:rotate(90deg);border-radius:0}.leaflet-control-minimap-toggle-display{background-image:url(images/toggle.svg);background-size:cover;position:absolute;border-radius:3px 0 0}.leaflet-oldie .leaflet-control-minimap-toggle-display{background-image:url(images/toggle.png)}.leaflet-control-minimap-toggle-display-bottomright{bottom:0;right:0}.leaflet-control-minimap-toggle-display-topleft{top:0;left:0;-webkit-transform:rotate(180deg);transform:rotate(180deg)}.leaflet-control-minimap-toggle-display-bottomleft{bottom:0;left:0;-webkit-transform:rotate(90deg);transform:rotate(90deg)}.leaflet-control-minimap-toggle-display-topright{top:0;right:0;-webkit-transform:rotate(270deg);transform:rotate(270deg)}.leaflet-oldie .leaflet-control-minimap{border:1px solid #999}.leaflet-oldie .leaflet-control-minimap a{background-color:#fff}.leaflet-oldie .leaflet-control-minimap a.minimized{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2)} \ No newline at end of file diff --git a/worldmap/leaflet/Control.MiniMap.min.js b/worldmap/leaflet/Control.MiniMap.min.js new file mode 100644 index 0000000..9158b1f --- /dev/null +++ b/worldmap/leaflet/Control.MiniMap.min.js @@ -0,0 +1 @@ +(function(factory,window){if(typeof define==="function"&&define.amd){define(["leaflet"],factory)}else if(typeof exports==="object"){module.exports=factory(require("leaflet"))}if(typeof window!=="undefined"&&window.L){window.L.Control.MiniMap=factory(L);window.L.control.minimap=function(layer,options){return new window.L.Control.MiniMap(layer,options)}}})(function(L){var MiniMap=L.Control.extend({includes:L.Evented?L.Evented.prototype:L.Mixin.Events,options:{position:"bottomright",toggleDisplay:false,zoomLevelOffset:-5,zoomLevelFixed:false,centerFixed:false,zoomAnimation:false,autoToggleDisplay:false,minimized:false,width:150,height:150,collapsedWidth:19,collapsedHeight:19,aimingRectOptions:{color:"#ff7800",weight:1,clickable:false},shadowRectOptions:{color:"#000000",weight:1,clickable:false,opacity:0,fillOpacity:0},strings:{hideText:"Hide MiniMap",showText:"Show MiniMap"},mapOptions:{}},initialize:function(layer,options){L.Util.setOptions(this,options);this.options.aimingRectOptions.clickable=false;this.options.shadowRectOptions.clickable=false;this._layer=layer},onAdd:function(map){this._mainMap=map;this._container=L.DomUtil.create("div","leaflet-control-minimap");this._container.style.width=this.options.width+"px";this._container.style.height=this.options.height+"px";L.DomEvent.disableClickPropagation(this._container);L.DomEvent.on(this._container,"mousewheel",L.DomEvent.stopPropagation);var mapOptions={attributionControl:false,dragging:!this.options.centerFixed,zoomControl:false,zoomAnimation:this.options.zoomAnimation,autoToggleDisplay:this.options.autoToggleDisplay,touchZoom:this.options.centerFixed?"center":!this._isZoomLevelFixed(),scrollWheelZoom:this.options.centerFixed?"center":!this._isZoomLevelFixed(),doubleClickZoom:this.options.centerFixed?"center":!this._isZoomLevelFixed(),boxZoom:!this._isZoomLevelFixed(),crs:map.options.crs};mapOptions=L.Util.extend(this.options.mapOptions,mapOptions);this._miniMap=new L.Map(this._container,mapOptions);this._miniMap.addLayer(this._layer);this._mainMapMoving=false;this._miniMapMoving=false;this._userToggledDisplay=false;this._minimized=false;if(this.options.toggleDisplay){this._addToggleButton()}this._miniMap.whenReady(L.Util.bind(function(){this._aimingRect=L.rectangle(this._mainMap.getBounds(),this.options.aimingRectOptions).addTo(this._miniMap);this._shadowRect=L.rectangle(this._mainMap.getBounds(),this.options.shadowRectOptions).addTo(this._miniMap);this._mainMap.on("moveend",this._onMainMapMoved,this);this._mainMap.on("move",this._onMainMapMoving,this);this._miniMap.on("movestart",this._onMiniMapMoveStarted,this);this._miniMap.on("move",this._onMiniMapMoving,this);this._miniMap.on("moveend",this._onMiniMapMoved,this)},this));return this._container},addTo:function(map){L.Control.prototype.addTo.call(this,map);var center=this.options.centerFixed||this._mainMap.getCenter();this._miniMap.setView(center,this._decideZoom(true));this._setDisplay(this.options.minimized);return this},onRemove:function(map){this._mainMap.off("moveend",this._onMainMapMoved,this);this._mainMap.off("move",this._onMainMapMoving,this);this._miniMap.off("moveend",this._onMiniMapMoved,this);this._miniMap.removeLayer(this._layer)},changeLayer:function(layer){this._miniMap.removeLayer(this._layer);this._layer=layer;this._miniMap.addLayer(this._layer)},_addToggleButton:function(){this._toggleDisplayButton=this.options.toggleDisplay?this._createButton("",this._toggleButtonInitialTitleText(),"leaflet-control-minimap-toggle-display leaflet-control-minimap-toggle-display-"+this.options.position,this._container,this._toggleDisplayButtonClicked,this):undefined;this._toggleDisplayButton.style.width=this.options.collapsedWidth+"px";this._toggleDisplayButton.style.height=this.options.collapsedHeight+"px"},_toggleButtonInitialTitleText:function(){if(this.options.minimized){return this.options.strings.showText}else{return this.options.strings.hideText}},_createButton:function(html,title,className,container,fn,context){var link=L.DomUtil.create("a",className,container);link.innerHTML=html;link.href="#";link.title=title;var stop=L.DomEvent.stopPropagation;L.DomEvent.on(link,"click",stop).on(link,"mousedown",stop).on(link,"dblclick",stop).on(link,"click",L.DomEvent.preventDefault).on(link,"click",fn,context);return link},_toggleDisplayButtonClicked:function(){this._userToggledDisplay=true;if(!this._minimized){this._minimize()}else{this._restore()}},_setDisplay:function(minimize){if(minimize!==this._minimized){if(!this._minimized){this._minimize()}else{this._restore()}}},_minimize:function(){if(this.options.toggleDisplay){this._container.style.width=this.options.collapsedWidth+"px";this._container.style.height=this.options.collapsedHeight+"px";this._toggleDisplayButton.className+=" minimized-"+this.options.position;this._toggleDisplayButton.title=this.options.strings.showText}else{this._container.style.display="none"}this._minimized=true;this._onToggle()},_restore:function(){if(this.options.toggleDisplay){this._container.style.width=this.options.width+"px";this._container.style.height=this.options.height+"px";this._toggleDisplayButton.className=this._toggleDisplayButton.className.replace("minimized-"+this.options.position,"");this._toggleDisplayButton.title=this.options.strings.hideText}else{this._container.style.display="block"}this._minimized=false;this._onToggle()},_onMainMapMoved:function(e){if(!this._miniMapMoving){var center=this.options.centerFixed||this._mainMap.getCenter();this._mainMapMoving=true;this._miniMap.setView(center,this._decideZoom(true));this._setDisplay(this._decideMinimized())}else{this._miniMapMoving=false}this._aimingRect.setBounds(this._mainMap.getBounds())},_onMainMapMoving:function(e){this._aimingRect.setBounds(this._mainMap.getBounds())},_onMiniMapMoveStarted:function(e){if(!this.options.centerFixed){var lastAimingRect=this._aimingRect.getBounds();var sw=this._miniMap.latLngToContainerPoint(lastAimingRect.getSouthWest());var ne=this._miniMap.latLngToContainerPoint(lastAimingRect.getNorthEast());this._lastAimingRectPosition={sw:sw,ne:ne}}},_onMiniMapMoving:function(e){if(!this.options.centerFixed){if(!this._mainMapMoving&&this._lastAimingRectPosition){this._shadowRect.setBounds(new L.LatLngBounds(this._miniMap.containerPointToLatLng(this._lastAimingRectPosition.sw),this._miniMap.containerPointToLatLng(this._lastAimingRectPosition.ne)));this._shadowRect.setStyle({opacity:1,fillOpacity:.3})}}},_onMiniMapMoved:function(e){if(!this._mainMapMoving){this._miniMapMoving=true;this._mainMap.setView(this._miniMap.getCenter(),this._decideZoom(false));this._shadowRect.setStyle({opacity:0,fillOpacity:0})}else{this._mainMapMoving=false}},_isZoomLevelFixed:function(){var zoomLevelFixed=this.options.zoomLevelFixed;return this._isDefined(zoomLevelFixed)&&this._isInteger(zoomLevelFixed)},_decideZoom:function(fromMaintoMini){if(!this._isZoomLevelFixed()){if(fromMaintoMini){return this._mainMap.getZoom()+this.options.zoomLevelOffset}else{var currentDiff=this._miniMap.getZoom()-this._mainMap.getZoom();var proposedZoom=this._miniMap.getZoom()-this.options.zoomLevelOffset;var toRet;if(currentDiff>this.options.zoomLevelOffset&&this._mainMap.getZoom()this._lastMiniMapZoom){toRet=this._mainMap.getZoom()+1;this._miniMap.setZoom(this._miniMap.getZoom()-1)}else{toRet=this._mainMap.getZoom()}}else{toRet=proposedZoom}this._lastMiniMapZoom=this._miniMap.getZoom();return toRet}}else{if(fromMaintoMini){return this.options.zoomLevelFixed}else{return this._mainMap.getZoom()}}},_decideMinimized:function(){if(this._userToggledDisplay){return this._minimized}if(this.options.autoToggleDisplay){if(this._mainMap.getBounds().contains(this._miniMap.getBounds())){return true}return false}return this._minimized},_isInteger:function(value){return typeof value==="number"},_isDefined:function(value){return typeof value!=="undefined"},_onToggle:function(){L.Util.requestAnimFrame(function(){L.DomEvent.on(this._container,"transitionend",this._fireToggleEvents,this);if(!L.Browser.any3d){L.Util.requestAnimFrame(this._fireToggleEvents,this)}},this)},_fireToggleEvents:function(){L.DomEvent.off(this._container,"transitionend",this._fireToggleEvents,this);var data={minimized:this._minimized};this.fire(this._minimized?"minimize":"restore",data);this.fire("toggle",data)}});L.Map.mergeOptions({miniMapControl:false});L.Map.addInitHook(function(){if(this.options.miniMapControl){this.miniMapControl=(new MiniMap).addTo(this)}});return MiniMap},window); \ No newline at end of file diff --git a/worldmap/leaflet/images/toggle.svg b/worldmap/leaflet/images/toggle.svg new file mode 100644 index 0000000..b293270 --- /dev/null +++ b/worldmap/leaflet/images/toggle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/worldmap/worldmap.js b/worldmap/worldmap.js index daebb3e..d15ce2b 100644 --- a/worldmap/worldmap.js +++ b/worldmap/worldmap.js @@ -23,6 +23,7 @@ var inIframe = false; var showUserMenu = true; var showLayerMenu = true; var showMouseCoords = false; +var minimap; var sidebyside; var layercontrol; var drawingColour = "#910000"; @@ -1787,6 +1788,18 @@ function doCommand(cmd) { layercontrol.addBaseLayer(basemaps[cmd.map.name],cmd.map.name); } } + // Add or swap new minimap layer + if (cmd.map && cmd.map.hasOwnProperty("minimap")) { + if (minimap) { map.removeControl(minimap); } + if (cmd.map.minimap == false) { return; } + if (basemaps[cmd.map.minimap]) { + minimap = new L.Control.MiniMap(basemaps[cmd.map.minimap], cmd.map.opt).addTo(map); + } + else { + console.log("Invalid base layer for minimap:",cmd.map.minimap); + } + + } // Remove one or more map layers (base or overlay) if (cmd.map && cmd.map.hasOwnProperty("delete")) { if (!Array.isArray(cmd.map.delete)) { cmd.map.delete = [cmd.map.delete]; }