diff --git a/static/js/Map.SelectArea.min.js b/static/js/Map.SelectArea.min.js
new file mode 100644
index 0000000..60484e5
--- /dev/null
+++ b/static/js/Map.SelectArea.min.js
@@ -0,0 +1,142 @@
+/**
+ * L.Map.SelectArea - Area selection tool for leaflet
+ *
+ * @author Alexander Milevski
+ * @see https://github.com/w8r/leaflet-area-select
+ * @license MIT
+ * @preserve
+ */
+// UMD
+!function(t){var o;if("function"==typeof define&&define.amd)
+// AMD
+define(["leaflet"],t);else if("undefined"!=typeof module)
+// Node/CommonJS
+o=require("leaflet"),module.exports=t(o);else{
+// Browser globals
+if(void 0===window.L)throw new Error("Leaflet must be loaded first");t(window.L)}}(function(a){function t(){return!0}
+/**
+ * @class L.Map.SelectArea
+ * @extends {L.Map.BoxZoom}
+ */
+a.Map.SelectArea=a.Map.BoxZoom.extend({statics:{
+/**
+ * @static
+ * @type {String}
+ */
+AREA_SELECTED:"areaselected",
+/**
+ * @static
+ * @type {String}
+ */
+AREA_SELECT_START:"areaselectstart",
+/**
+ * @static
+ * @type {String}
+ */
+AREA_SELECTION_TOGGLED:"areaselecttoggled"},options:{shiftKey:!1,ctrlKey:!0,validate:t,autoDisable:!1,cursor:"crosshair"},
+/**
+ * @param {L.Map} map
+ * @constructor
+ */
+initialize:function(t,o){a.Util.setOptions(this,o||{}),a.Map.BoxZoom.prototype.initialize.call(this,t),
+/**
+ * @type {Function}
+ */
+this._validate=null,
+/**
+ * @type {Boolean}
+ */
+this._moved=!1,
+/**
+ * @type {Boolean}
+ */
+this._autoDisable=!this.options.ctrlKey&&this.options.autoDisable,
+/**
+ * @type {L.Point}
+ */
+this._lastLayerPoint=null,
+/**
+ * @type {String|Null}
+ */
+this._beforeCursor=null,this.setValidate(this.options.validate),this.setAutoDisable(this.options.autoDisable)},
+/**
+ * @param {Function=} validate
+ * @return {SelectArea}
+ */
+setValidate:function(o){var e=this;return"function"!=typeof o&&(o=t),this._validate=function(t){return o.call(e,t)},this},
+/**
+ * @param {Boolean} autoDisable
+ */
+setAutoDisable:function(t){this._autoDisable=!!t},
+/**
+ * @param {Boolean} on
+ */
+setControlKey:function(t){var o=this._enabled;o&&this.disable(),this.options.ctrlKey=!!t,t&&(this.options.shiftKey=!1),o&&this.enable()},
+/**
+ * @param {Boolean} on
+ */
+setShiftKey:function(t){var o=this._enabled;o&&this.disable(),this.options.shiftKey=!!t,t&&(this.options.ctrlKey=!1),o&&this.enable()},
+/**
+ * Disable dragging or zoombox
+ * @param {Function=} validate
+ * @param {Boolean=} autoDisable
+ */
+enable:function(t,o){this.options.shiftKey?this._map.boxZoom&&this._map.boxZoom.disable():this.options.ctrlKey||this._map.dragging.disable(),a.Map.BoxZoom.prototype.enable.call(this),this.options.ctrlKey||this._setCursor(),t&&this.setValidate(t),this.setAutoDisable(o),this._map.fire(a.Map.SelectArea.AREA_SELECTION_TOGGLED)},
+/**
+ * Re-enable box zoom or dragging
+ */
+disable:function(){a.Map.BoxZoom.prototype.disable.call(this),this.options.ctrlKey||this._restoreCursor(),this.options.shiftKey?this._map.boxZoom&&this._map.boxZoom.enable():this._map.dragging.enable(),this._map.fire(a.Map.SelectArea.AREA_SELECTION_TOGGLED)},
+/**
+ * Also listen to ESC to cancel interaction
+ * @override
+ */
+addHooks:function(){a.Map.BoxZoom.prototype.addHooks.call(this),a.DomEvent.on(document,"keyup",this._onKeyUp,this).on(document,"keydown",this._onKeyPress,this).on(document,"contextmenu",this._onMouseDown,this).on(window,"blur",this._onBlur,this),this._map.on("dragstart",this._onMouseDown,this)},
+/**
+ * @override
+ */
+removeHooks:function(){a.Map.BoxZoom.prototype.removeHooks.call(this),a.DomEvent.off(document,"keyup",this._onKeyUp,this).off(document,"keydown",this._onKeyPress,this).off(document,"contextmenu",this._onMouseDown,this).off(window,"blur",this._onBlur,this),this._map.off("dragstart",this._onMouseDown,this)},
+/**
+ * @override
+ */
+_onMouseDown:function(t){if(this._moved=!1,this._lastLayerPoint=null,this.options.shiftKey&&!t.shiftKey||this.options.ctrlKey&&!t.ctrlKey||1!==t.which&&1!==t.button)return!1;a.DomEvent.stop(t);var o=this._map.mouseEventToLayerPoint(t);if(!this._validate(o))return!1;a.DomUtil.disableTextSelection(),a.DomUtil.disableImageDrag(),this._startLayerPoint=o,a.DomEvent.on(document,"mousemove",this._onMouseMove,this).on(document,"mouseup",this._onMouseUp,this).on(document,"keydown",this._onKeyDown,this)},
+/**
+ * @override
+ */
+_onMouseMove:function(t){this._moved||(this._box=a.DomUtil.create("div","leaflet-zoom-box",this._pane),a.DomUtil.setPosition(this._box,this._startLayerPoint),this._map.fire(a.Map.SelectArea.AREA_SELECT_START));var o,e=this._startLayerPoint,i=this._box,s=this._map.mouseEventToLayerPoint(t),n=s.subtract(e);this._validate(s)&&(this._lastLayerPoint=s,o=new a.Point(Math.min(s.x,e.x),Math.min(s.y,e.y)),a.DomUtil.setPosition(i,o),this._moved=!0,
+// TODO refactor: remove hardcoded 4 pixels
+i.style.width=Math.max(0,Math.abs(n.x)-4)+"px",i.style.height=Math.max(0,Math.abs(n.y)-4)+"px")},
+/**
+ * General on/off toggle
+ * @param {KeyboardEvent} e
+ */
+_onKeyUp:function(t){27===t.keyCode?this._moved&&this._box&&this._finish():this.options.ctrlKey&&(this._restoreCursor(),this._map.dragging.enable())},
+/**
+ * Key down listener to enable on ctrl-press
+ * @param {KeyboardEvent} e
+ */
+_onKeyPress:function(t){this.options.ctrlKey&&(t.ctrlKey||"dragstart"===t.type)&&null===this._beforeCursor&&(this._setCursor(),this._map.dragging._draggable._onUp(t),// hardcore
+this._map.dragging.disable())},
+/**
+ * Window blur listener to restore state
+ * @param {Event} e
+ */
+_onBlur:function(t){this._restoreCursor(),this._map.dragging.enable()},
+/**
+ * Set crosshair cursor
+ */
+_setCursor:function(){this._beforeCursor=this._container.style.cursor,this._container.style.cursor=this.options.cursor},
+/**
+ * Restore status quo cursor
+ */
+_restoreCursor:function(){this._container.style.cursor=this._beforeCursor,this._beforeCursor=null},
+/**
+ * @override
+ */
+_onMouseUp:function(t){this._finish();var o,e=this._map,i=this._lastLayerPoint;// map.mouseEventToLayerPoint(e);
+i&&!this._startLayerPoint.equals(i)&&(a.DomEvent.stop(t),o=new a.LatLngBounds(e.layerPointToLatLng(this._startLayerPoint),e.layerPointToLatLng(i)),
+//map.fitBounds(bounds);
+this._autoDisable?this.disable():this._restoreCursor(),this._moved=!1,a.Util.requestAnimFrame(function(){e.fire(a.Map.SelectArea.AREA_SELECTED,{bounds:o})}))}}),
+// expose setting
+a.Map.mergeOptions({selectArea:!1}),
+// register hook
+a.Map.addInitHook("addHandler","selectArea",a.Map.SelectArea)});
diff --git a/static/js/map.js b/static/js/map.js
index dfea31a..ea69879 100644
--- a/static/js/map.js
+++ b/static/js/map.js
@@ -138,6 +138,33 @@ function refreshDatapoints(deveui, start, stop) {
}
$(document).ready(function () {
+ var greenzone = "";
+ $("#modal-yes").click(function () {
+ $("#yesnomodal").removeClass("is-active");
+ $.ajax({
+ url: "save_tracker_greenzone",
+ type: "get", //send it through get method
+ dataType: "json",
+ data: {
+ deveui: deveui,
+ greenzone: greenzone
+ },
+ success: function (response) {
+ if (response.rc == 0) {
+ $('#greenzone_'+$('#deveui').html()).html($('#greenzone').val());
+ }
+ },
+ error: function (xhr) {
+ //Do Something to handle error
+ console.log("Somethin went wrong in ajax save_tracker_greenzone...");
+ }
+ });
+ });
+
+ $("#modal-no").click(function () {
+ $("#yesnomodal").removeClass("is-active");
+ });
+
params = "deveui=" + deveui + "&alias=" + alias + "&start=" + s_start + "&stop=" + s_stop;
$("#btn_download").attr("href", "/downloadmetrics?" + params);
$("#btn_download").attr("download", getDownloadFilename(deveui, s_start, s_stop));
@@ -145,10 +172,16 @@ $(document).ready(function () {
crs: L.CRS.EPSG3857,
zoomControl: true,
maxBounds: boundsSwitzerland,
- doubleClickZoom: false
+ doubleClickZoom: false,
+ selectArea: true
});
map.setMinZoom(map.getBoundsZoom(map.options.maxBounds));
+ map.on('areaselected', (e) => {
+ greenzone = (e.bounds.toBBoxString()); // lon, lat, lon, lat
+ $("#yesnomodal").addClass("is-active");
+ });
+
map.on('dblclick', function (e) {
map.fitBounds(bounds, { padding: [20, 20] });
});
diff --git a/static/js/tracker.js b/static/js/tracker.js
index 02f3c28..2ba69ee 100644
--- a/static/js/tracker.js
+++ b/static/js/tracker.js
@@ -10,7 +10,7 @@ function validate(what, text) {
} else if (what == 'email') {
var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
} else if (what == 'greenzone') {
- var re = /^$|^[0-9]+\.[0-9]+,[0-9]+\.[0-9],[0-9]+\.[0-9],[0-9]+\.[0-9]$/;
+ var re = /^$|^[0-9]+\.[0-9]+,[0-9]+\.[0-9]+,[0-9]+\.[0-9]+,[0-9]+\.[0-9]+$/;
}
return re.test(text);
diff --git a/tracker.go b/tracker.go
index 57e0186..0ef9727 100644
--- a/tracker.go
+++ b/tracker.go
@@ -126,10 +126,10 @@ func save_tracker_settingsHandler(response http.ResponseWriter, request *http.Re
}
mygreenzone := greenzone[0]
- match3, _ := regexp.MatchString(`^$|^[0-9]+\.[0-9]+,[0-9]+\.[0-9],[0-9]+\.[0-9],[0-9]+\.[0-9]$`, mygreenzone)
+ match3, _ := regexp.MatchString(`^$|^[0-9]+\.[0-9]+,[0-9]+\.[0-9]+,[0-9]+\.[0-9]+,[0-9]+\.[0-9]+$`, mygreenzone)
if !(match3) {
- log.Println("Url Param 'email' is not valid")
- fmt.Fprintf(response, "{ \"rc\": 17, \"msg\": \"email is not valid, must be in in format max.mustermann@example.com\" }")
+ log.Println("Url Param 'greenzone' is not valid")
+ fmt.Fprintf(response, "{ \"rc\": 17, \"msg\": \"greenzone is not valid, must be in in 123.45,123.45,123.45,123.45\" }")
return
}
@@ -157,3 +157,64 @@ func save_tracker_settingsHandler(response http.ResponseWriter, request *http.Re
fmt.Fprintf(response, "{ \"rc\": 7, \"msg\": \"Only available for logged in users\" }")
}
}
+
+func save_tracker_greenzoneHandler(response http.ResponseWriter, request *http.Request) {
+ name := getUserName(request)
+ if name != "" {
+
+ deveui, ok := request.URL.Query()["deveui"]
+
+ if !ok || len(deveui[0]) < 1 {
+ log.Println("Url Param 'deveui' is missing")
+ fmt.Fprintf(response, "{ \"rc\": 1, \"msg\": \"deveui must be specified in URL\" }")
+ return
+ }
+ // Query()["deveui"] will return an array of items,
+ // we only want the single item.
+ mydeveui := deveui[0]
+
+ if len(mydeveui) != 16 {
+ log.Println("specified 'deveui' has invalid length")
+ fmt.Fprintf(response, "{ \"rc\": 8, \"msg\": \"specified deveui has invalid length\" }")
+ return
+ }
+
+ if !(Contains(getMyDevs(name), mydeveui)) {
+ log.Println("specified 'deveui' does not belong to this user")
+ fmt.Fprintf(response, "{ \"rc\": 2, \"msg\": \"specified deveui does not belong to this user\" }")
+ return
+ }
+
+ log.Println("Url Param 'deveui' is: " + string(mydeveui))
+
+ greenzone, ok1 := request.URL.Query()["greenzone"]
+
+ if !ok1 {
+ log.Println("Url Param 'greenzone' is missing")
+ fmt.Fprintf(response, "{ \"rc\": 3, \"msg\": \"greenzone must be specified in URL\" }")
+ return
+ }
+ mygreenzone := greenzone[0]
+
+ match, _ := regexp.MatchString(`^$|^[0-9]+\.[0-9]+,[0-9]+\.[0-9]+,[0-9]+\.[0-9]+,[0-9]+\.[0-9]+$`, mygreenzone)
+ if !(match) {
+ log.Println("Url Param 'greenzone' is not valid")
+ fmt.Fprintf(response, "{ \"rc\": 17, \"msg\": \"greenzone is not valid, must be in in 123.45,123.45,123.45,123.45\" }")
+ return
+ }
+
+ // now we try to save the settings
+ err := updateTrackerGreenzone(mydeveui, mygreenzone)
+
+ if err != nil {
+ log.Println("Error to Update Greenzone")
+ fmt.Fprintf(response, "{ \"rc\": 6, \"msg\": \"error with updating greenzone\" }")
+ return
+ } else {
+ fmt.Fprintf(response, "{ \"rc\": 0, \"msg\": \"SUCCESS\" }")
+ }
+
+ } else {
+ fmt.Fprintf(response, "{ \"rc\": 7, \"msg\": \"Only available for logged in users\" }")
+ }
+}