diff --git a/.gitignore b/.gitignore index 01c8bf8f9..aad4cc45b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ -node_modules coverage todo.txt *.swp *.swo package-lock.json bower_components +.vscode +node_modules diff --git a/Gruntfile.js b/Gruntfile.js index ce5e68a92..1cd4fef78 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -30,6 +30,7 @@ module.exports = function(grunt) { warpWebGl: false, EXIF: false, alert: false, + processedPoints: false, // Mocha diff --git a/dist/leaflet.distortableimage.css b/dist/leaflet.distortableimage.css index 21d3f5bb3..555d0892a 100644 --- a/dist/leaflet.distortableimage.css +++ b/dist/leaflet.distortableimage.css @@ -1,3 +1,9 @@ +body { + margin:0; + background-color: darkgreen; + overflow: hidden; +} + #imgcontainer { position:relative; width: 100%; @@ -49,6 +55,7 @@ img.leaflet-image-layer.selected { font-weight: 400; letter-spacing: 0.5px; line-height: 1.2; + border-radius: 5px; } .l-container table th{ @@ -89,3 +96,23 @@ span { letter-spacing: 1.2px; } +.loader-container { + width: 100px; + height: 100vh; + margin-top:30vh; +} + +#matcher-button { + position: absolute; + bottom: 20px; + left: 20px; + background-color: rgba(255, 255, 255, .6); + border: none; + font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; + color: black; + cursor: pointer; + z-index: 500; + border-radius: 5px; + padding: 5px; + font-weight: bold; +} diff --git a/dist/leaflet.distortableimage.js b/dist/leaflet.distortableimage.js index 6f5ee9478..18b1e90ac 100644 --- a/dist/leaflet.distortableimage.js +++ b/dist/leaflet.distortableimage.js @@ -1040,6 +1040,27 @@ var EditOverlayAction = LeafletToolbar.ToolbarAction.extend({ LeafletToolbar.ToolbarAction.prototype.initialize.call(this, options); } }), +// make one for initializing matcher also + Stitcher = EditOverlayAction.extend({ + options: { + toolbarIcon: { + html: '', + tooltip: 'Enable stitcher' + } + }, + + addHooks: function() { + var map = this._map; + var overlay = this._overlay; + try { + stitcher(processedPoints, overlay, map); // jshint ignore:line + } catch(err) { + console.error('err: check if matcher is initialized properly and correct parameters are supplied \n', err); + } + map.setView(overlay.getCorner(2), 13); + this.disable(); + } + }), ToggleTransparency = EditOverlayAction.extend({ options: { toolbarIcon: { @@ -1186,7 +1207,8 @@ L.DistortableImage.EditToolbar = LeafletToolbar.Popup.extend({ ToggleRotateScale, ToggleExport, EnableEXIF, - ToggleOrder + ToggleOrder, + Stitcher ] }, @@ -1310,29 +1332,29 @@ L.DistortableImage.Edit = L.Handler.extend({ var overlay = this._overlay, i; - this._lockHandles = new L.LayerGroup(); + this._lockHandles = L.layerGroup(); for (i = 0; i < 4; i++) { this._lockHandles.addLayer( new L.LockHandle(overlay, i, { draggable: false }) ); } - this._distortHandles = new L.LayerGroup(); + this._distortHandles = L.layerGroup(); for (i = 0; i < 4; i++) { this._distortHandles.addLayer(new L.DistortHandle(overlay, i)); } - this._rotateHandles = new L.LayerGroup(); // individual rotate + this._rotateHandles = L.layerGroup(); // individual rotate for (i = 0; i < 4; i++) { this._rotateHandles.addLayer(new L.RotateHandle(overlay, i)); } - this._scaleHandles = new L.LayerGroup(); + this._scaleHandles = L.layerGroup(); for (i = 0; i < 4; i++) { this._scaleHandles.addLayer(new L.ScaleHandle(overlay, i)); } - this._rotateScaleHandles = new L.LayerGroup(); // handle includes rotate AND scale + this._rotateScaleHandles = L.layerGroup(); // handle includes rotate AND scale for (i = 0; i < 4; i++) { this._rotateScaleHandles.addLayer(new L.RotateScaleHandle(overlay, i)); } @@ -1780,7 +1802,8 @@ L.DistortableImage.Keymapper = L.Control.extend({ ""; return el_wrapper; } -}); +}); + L.Map.mergeOptions({ boxSelector: true, boxZoom: false }); // used for multiple image select. Temporarily disabled until click diff --git a/examples/dot.png b/examples/dot.png new file mode 100644 index 000000000..3bc63ef7d Binary files /dev/null and b/examples/dot.png differ diff --git a/examples/index.html b/examples/index.html index cf6e7d9a0..37e20b67f 100644 --- a/examples/index.html +++ b/examples/index.html @@ -1,121 +1,118 @@ - - Leaflet.DistortableImage Example - - + + Leaflet.DistortableImage Example + - - - - - + - - - - + + + + + + + + + + + + + + + - - + + - - - - -
- -
+ + + -
- - - L.DomEvent.on(img._image, "load", img.editing.enable, img.editing); - })(); - diff --git a/examples/leaflet.gif b/examples/leaflet.gif new file mode 100644 index 000000000..76021b199 Binary files /dev/null and b/examples/leaflet.gif differ diff --git a/package-lock.json b/package-lock.json index d7d178473..6ddb81d93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1732,7 +1732,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -1753,12 +1754,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1773,17 +1776,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -1900,7 +1906,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -1912,6 +1919,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1926,6 +1934,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -1933,12 +1942,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1957,6 +1968,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -2037,7 +2049,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -2049,6 +2062,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -2134,7 +2148,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -2170,6 +2185,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -2189,6 +2205,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2232,12 +2249,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -3617,6 +3636,10 @@ "stack-trace": "0.0.10" } }, + "matcher-core": { + "version": "git+https://github.com/rexagod/matcher-core.git#b982255bb12ae5bbfe59da9e19ff5f6abc5d6797", + "from": "git+https://github.com/rexagod/matcher-core.git#main" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", diff --git a/package.json b/package.json index 66f0ecb03..54fe9894d 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,8 @@ }, "homepage": "https://github.com/publiclab/Leaflet.DistortableImage", "dependencies": { - "grunt-cli": "^1.2.0" + "grunt-cli": "^1.2.0", + "matcher-core": "https://github.com/rexagod/matcher-core#main" }, "devDependencies": { "chai": "^4.1.2", diff --git a/src/edit/DistortableImage.EditToolbar.js b/src/edit/DistortableImage.EditToolbar.js index 8538bbed9..2e410b986 100644 --- a/src/edit/DistortableImage.EditToolbar.js +++ b/src/edit/DistortableImage.EditToolbar.js @@ -8,6 +8,27 @@ var EditOverlayAction = LeafletToolbar.ToolbarAction.extend({ LeafletToolbar.ToolbarAction.prototype.initialize.call(this, options); } }), +// make one for initializing matcher also + Stitcher = EditOverlayAction.extend({ + options: { + toolbarIcon: { + html: '', + tooltip: 'Enable stitcher' + } + }, + + addHooks: function() { + var map = this._map; + var overlay = this._overlay; + try { + stitcher(processedPoints, overlay, map); // jshint ignore:line + } catch(err) { + console.error('err: check if matcher is initialized properly and correct parameters are supplied \n', err); + } + map.setView(overlay.getCorner(2), 13); + this.disable(); + } + }), ToggleTransparency = EditOverlayAction.extend({ options: { toolbarIcon: { @@ -154,7 +175,8 @@ L.DistortableImage.EditToolbar = LeafletToolbar.Popup.extend({ ToggleRotateScale, ToggleExport, EnableEXIF, - ToggleOrder + ToggleOrder, + Stitcher ] }, diff --git a/src/edit/tools/DistortableImage.Keymapper.js b/src/edit/tools/DistortableImage.Keymapper.js index 8738b7a5e..e2a9c035e 100644 --- a/src/edit/tools/DistortableImage.Keymapper.js +++ b/src/edit/tools/DistortableImage.Keymapper.js @@ -21,4 +21,4 @@ L.DistortableImage.Keymapper = L.Control.extend({ ""; return el_wrapper; } -}); \ No newline at end of file +}); diff --git a/src/util/matcher/init_.js b/src/util/matcher/init_.js new file mode 100644 index 000000000..31afe4270 --- /dev/null +++ b/src/util/matcher/init_.js @@ -0,0 +1,4 @@ +function init_(add) { // jshint ignore:line + var x = add(); + return {map: x.map, L_images: x.L_img_array}; + } diff --git a/src/util/matcher/init_with_matcher.js b/src/util/matcher/init_with_matcher.js new file mode 100644 index 000000000..588ae4eab --- /dev/null +++ b/src/util/matcher/init_with_matcher.js @@ -0,0 +1,23 @@ +/* jshint ignore:start */ +function init_with_matcher(add, paths) { + Promise.resolve( + new orbify(paths[0], paths[1], { + browser: true + }).utils + ).then(function(utils) { + var array = []; + var obj = init_(add); + var images = document.getElementsByClassName( + "leaflet-image-layer leaflet-zoom-animated" + ); + var ext = function(e) { + setInterval(function() { + projector(utils, e, array, obj); + }, 10); + }; + for (var i = 0; i < images.length; i++) { + L.DomEvent.on(images[i], "click", ext); + } + }); +} +/* jshint ignore:end */ diff --git a/src/util/matcher/projector.js b/src/util/matcher/projector.js new file mode 100644 index 000000000..e9127fe81 --- /dev/null +++ b/src/util/matcher/projector.js @@ -0,0 +1,86 @@ +function projector(utils, e, array, obj) { // jshint ignore:line + var L_img_array = obj.L_images; + var map = obj.map; + document.querySelector("#map > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-marker-pane").innerHTML = ""; // part of this is the toolbar + if(document.querySelectorAll("#map > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > svg > g > path").length) { + [].slice.call(document.querySelectorAll("#map > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > svg > g > path")).slice(0,3).map(function(x) { + x.parentNode.removeChild(x); + }); + } + function addLine(line_coordinates, map) { + return L.polyline(line_coordinates).addTo(map); + } + var match_points = utils.matches; + var icon = L.icon({ + iconUrl: "dot.png", + iconSize: [5, 5], + iconAnchor: [0, 0], + popupAnchor: [2, 2] + }); + var dot = function(x, y, c){ + return L.marker([x, y], { icon: icon }).addTo(map).bindPopup(JSON.stringify(c)); + }; + array.push(e.target); + if (array.length >= 2) { + array = array.slice(-2); + var A = array[0]; + var B = array[1]; + for (var p in L_img_array) { + if (L_img_array[p]._image === A) { + array[0] = L_img_array[p]; + } + if (L_img_array[p]._image === B) { + array[1] = L_img_array[p]; + } + } + var idx = 2; + var processedPoints = {points: [], images: [], confidences: []}; + for (var i=0; i corners[1].lng && + processedPoints.points[i][j].lng < center.lng + ) { + if ( + processedPoints.points[i][j].lat > corners[3].lat && + processedPoints.points[i][j].lat < center.lat + ) { + sectors.s10[i].push(processedPoints.points[i][j]); + } else { + sectors.s00[i].push(processedPoints.points[i][j]); + } + } else { + if ( + processedPoints.points[i][j].lat > corners[2].lat && + processedPoints.points[i][j].lat < center.lat + ) { + sectors.s11[i].push(processedPoints.points[i][j]); + } else { + sectors.s01[i].push(processedPoints.points[i][j]); + } + } + } + } + for (i=0; i max) { + max = sectors.population[0][0][i]; + max_idx = i; + } + if (sectors.population[0][0][i] < min) { + min = sectors.population[0][0][i]; + } + } + if (max !== min) { + var coordinates = sectors[Object.keys(sectors)[max_idx]][0]; + for (var u in processedPoints.points[0]) { + for (var v in coordinates) { + if (processedPoints.points[0][u] === coordinates[v]) { + if (processedPoints.confidences[0][u] > max_) { + max_ = processedPoints.confidences[0][u]; + } + } + } + } + var best_point = + processedPoints.points[0][processedPoints.confidences[0].indexOf(max_)]; + var corresponding_best_point = + processedPoints.points[1][processedPoints.confidences[0].indexOf(max_)]; + document.querySelector( + "#map > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-marker-pane" + ).innerHTML = ""; + if(document.querySelectorAll("#map > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > svg > g > path").length) { + [].slice.call(document.querySelectorAll("#map > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > svg > g > path")).slice(0,3).map(function(x) { + x.parentNode.removeChild(x); + }); + } + var lat_offset = -best_point.lat + corresponding_best_point.lat; + var lng_offset = -best_point.lng + corresponding_best_point.lng; + // revert this effect completely + overlay._corners[0] = [ + processedPoints.images[1].getCorner(0).lat - lat_offset, + processedPoints.images[1].getCorner(0).lng - lng_offset + ]; + overlay._corners[1] = [ + processedPoints.images[1].getCorner(1).lat - lat_offset, + processedPoints.images[1].getCorner(1).lng - lng_offset + ]; + overlay._corners[2] = [ + processedPoints.images[1].getCorner(2).lat - lat_offset, + processedPoints.images[1].getCorner(2).lng - lng_offset + ]; + overlay._corners[3] = [ + processedPoints.images[1].getCorner(3).lat - lat_offset, + processedPoints.images[1].getCorner(3).lng - lng_offset + ]; + var zoom_level = map.getZoom(); + map.setView(overlay.getCenter(), (zoom_level%2?zoom_level+1:zoom_level-1)); + L.DomEvent.on(overlay._image, 'mousedrag', overlay.editing.enable, overlay.editing); + } +}