diff --git a/README.md b/README.md index 956fdf5d..f0d20c8f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -## Widgets +## Widgets + [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](LICENSE) - select2: [site](https://select2.org/), [repo](https://github.com/select2/select2), license: MIT @@ -29,6 +30,8 @@ - imageHotArea [repo](https://github.com/TheNetworg/surveyjs-plugin-hotarea), licence: MIT +- leaflet [site](https://leafletjs.com/), license [MIT](http://spdx.org/licenses/MIT.html) + ## Getting started es5 examples: https://surveyjs.io/Examples/Library/?id=custom-widget-select2-tagbox diff --git a/package.json b/package.json index 19c529a2..643f054b 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "jquery": "^3.5.0", "jquery-bar-rating": "^1.2.2", "jquery-ui": "^1.13.0", + "leaflet": "^1.7.1", "live-server": "^1.2.0", "nouislider": "latest", "pretty-checkbox": "^3.0.3", diff --git a/src/leaflet.js b/src/leaflet.js new file mode 100644 index 00000000..12767859 --- /dev/null +++ b/src/leaflet.js @@ -0,0 +1,89 @@ +import L from 'leaflet'; + +var widget = { + name: "leaflet", + title: "Leaflet position", + iconName: "", + widgetIsLoaded: function () { + return typeof L != "undefined"; + }, + isFit: function (question) { + return question.getType() === 'leaflet'; + }, + + activatedByChanged: function (activatedBy) { + Survey.JsonObject.metaData.addClass("leaflet", [], null, "empty"); + + Survey.JsonObject.metaData.addProperties("leaflet", [ + {name: "height", default: 200}, + { name: "zoom", default: 13}, + {name: "useUserPosition", default: false}, + {name: "initialLatitude", default: 51.5}, + {name: "initialLongitude", default: -0.09}, + {name: "tileAddress", default: "https://{s}.tile.osm.org/{z}/{x}/{y}.png"}, + {name: "tileAttribution", default: '© OpenStreetMap contributors'} + ]); + }, + isDefaultRender: false, + htmlTemplate: "
", + afterRender: function (question, el) { + + + el.style.height = question.height+"px"; + var map = L.map('map'); + L.tileLayer(question.tileAddress, { + attribution: question.tileAttribution + }).addTo(map); + + var myMarker = L.marker([0, 0], {title: "location", alt: "Selected Location", draggable: true}).addTo(map); + + var onDragEnd = function(){ + var coord = String(myMarker.getLatLng()).split(','); + var lat = coord[0].split('('); + var lng = coord[1].split(')'); + myMarker.bindPopup("Moved to: " + lat[1] + ", " + lng[0] + "."); + question.value = {lng: lng[0], lat: lat[1]}; + } + + + myMarker.on('dragend', onDragEnd); + + if(question.useUserPosition){ + + map.locate({setView: true, watch: false}) + .on('locationfound', function(e){ + console.log("LOCATION", e); + var newLatLng = new L.LatLng(e.latitude, e.longitude); + myMarker.setLatLng(newLatLng); + map.setView([e.latitude, e.longitude], question.zoom); + }) + .on('locationerror', function(e){ + console.log(e); + }); + } else { + map.setView([question.initialLatitude, question.initialLongitude], question.zoom); + var newLatLng = new L.LatLng(question.initialLatitude, question.initialLongitude); + myMarker.setLatLng(newLatLng); + } + + var onReadOnlyChangedCallback = function() { + if (question.isReadOnly) { + myMarker.off('dragend', onDragEnd); + } else { + myMarker.on('dragend', onDragEnd); + } + } + + question.readOnlyChangedCallback = onReadOnlyChangedCallback; + onReadOnlyChangedCallback(); + }, + //Use it to destroy the widget. It is typically needed by jQuery widgets + willUnmount: function (question, el) { + //We do not need to clear anything in our simple example + //Here is the example to destroy the image picker + //var $el = $(el).find("select"); + //$el.data('picker').destroy(); + } +} + +Survey.CustomWidgetCollection.Instance.addCustomWidget(widget, "customtype"); \ No newline at end of file diff --git a/src/surveyjs-widgets.js b/src/surveyjs-widgets.js index 3caa7ffa..7d8f4bfb 100644 --- a/src/surveyjs-widgets.js +++ b/src/surveyjs-widgets.js @@ -13,3 +13,4 @@ export { default as bootstrapslider } from "./bootstrap-slider.js"; export { default as microphone } from "./microphone.js"; export { default as emotionsratings } from "./emotionsratings.js"; export { default as bootstrapdatepicker } from "./bootstrapdatepicker.js"; +export { default as leaflet } from "./leaflet.js"; diff --git a/webpack.config.js b/webpack.config.js index 2460df3d..e314e702 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -37,7 +37,8 @@ var widgets = [ "pretty-checkbox", "bootstrap-slider", "microphone", - "emotionsratings" + "emotionsratings", + "leaflet" ]; var dependencies = { @@ -52,7 +53,8 @@ var dependencies = { "pretty-checkbox": "^3.0.3", "bootstrap-slider": "^10.0.0", recordrtc: "^5.4.6", - "emotion-ratings": "^2.0.1" + "emotion-ratings": "^2.0.1", + "leaflet": "^1.7.1" }; var entry = {}; @@ -92,6 +94,7 @@ module.exports = function(options) { targetPackageJson.files.push(`widgets/${widget}.min.js`); targetPackageJson.files.push(`widgets/${widget}.min.js.map`); entry["widgets/" + widget] = path.join(__dirname, `./src/${widget}.js`); + } else { targetPackageJson.files.push(`${widget}.js`); targetPackageJson.files.push(`${widget}.min.js`); @@ -133,6 +136,12 @@ module.exports = function(options) { commonjs: "nouislider", amd: "nouislider" }, + leaflet: { + root: "L", + commonjs2: "L", + commonjs: "L", + amd: "L" + }, sortablejs: { root: "Sortable", commonjs2: "sortablejs", @@ -161,6 +170,7 @@ module.exports = function(options) { config.plugins = config.plugins.concat([ new CleanWebpackPlugin([outputFolder], { verbose: true }) ]); + } if (options.buildType === "prod") {