New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

leaflet-distortableimage

Package Overview
Dependencies
Maintainers
1
Versions
56
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

leaflet-distortableimage - npm Package Compare versions

Comparing version 0.3.0 to 0.4.0

.git/logs/refs/heads/readme

649

dist/leaflet.distortableimage.js

@@ -33,3 +33,9 @@ L.DomUtil = L.extend(L.DomUtil, {

return open + rotateString + ')';
},
toggleClass: function(el, className) {
var c = className;
return this.hasClass(el, c) ? this.removeClass(el, c) : this.addClass(el, c);
}
});

@@ -130,3 +136,90 @@

};
L.EXIF = function getEXIFdata(img) {
if (Object.keys(EXIF.getAllTags(img)).length !== 0) {
console.log(EXIF.getAllTags(img));
var GPS = EXIF.getAllTags(img),
altitude;
/* If the lat/lng is available. */
if (
typeof GPS.GPSLatitude !== "undefined" &&
typeof GPS.GPSLongitude !== "undefined"
) {
// sadly, encoded in [degrees,minutes,seconds]
// primitive value = GPS.GPSLatitude[x].numerator
var lat =
GPS.GPSLatitude[0] +
GPS.GPSLatitude[1] / 60 +
GPS.GPSLatitude[2] / 3600;
var lng =
GPS.GPSLongitude[0] +
GPS.GPSLongitude[1] / 60 +
GPS.GPSLongitude[2] / 3600;
if (GPS.GPSLatitudeRef !== "N") {
lat = lat * -1;
}
if (GPS.GPSLongitudeRef === "W") {
lng = lng * -1;
}
}
// Attempt to use GPS compass heading; will require
// some trig to calc corner points, which you can find below:
var angle = 0;
// "T" refers to "True north", so -90.
if (GPS.GPSImgDirectionRef === "T") {
angle =
(Math.PI / 180) *
(GPS.GPSImgDirection.numerator / GPS.GPSImgDirection.denominator - 90);
}
// "M" refers to "Magnetic north"
else if (GPS.GPSImgDirectionRef === "M") {
angle =
(Math.PI / 180) *
(GPS.GPSImgDirection.numerator / GPS.GPSImgDirection.denominator - 90);
} else {
console.log("No compass data found");
}
console.log("Orientation:", GPS.Orientation);
/* If there is orientation data -- i.e. landscape/portrait etc */
if (GPS.Orientation === 6) {
//CCW
angle += (Math.PI / 180) * -90;
} else if (GPS.Orientation === 8) {
//CW
angle += (Math.PI / 180) * 90;
} else if (GPS.Orientation === 3) {
//180
angle += (Math.PI / 180) * 180;
}
/* If there is altitude data */
if (
typeof GPS.GPSAltitude !== "undefined" &&
typeof GPS.GPSAltitudeRef !== "undefined"
) {
// Attempt to use GPS altitude:
// (may eventually need to find EXIF field of view for correction)
if (
typeof GPS.GPSAltitude !== "undefined" &&
typeof GPS.GPSAltitudeRef !== "undefined"
) {
altitude =
GPS.GPSAltitude.numerator / GPS.GPSAltitude.denominator +
GPS.GPSAltitudeRef;
} else {
altitude = 0; // none
}
}
} else {
alert("EXIF initialized. Press again to view data in console.");
}
};
L.EditHandle = L.Marker.extend({
initialize: function(overlay, corner, options) {

@@ -218,2 +311,3 @@ var markerOptions,

this.setLatLng(this._handled._corners[this._corner]);
L.DomUtil.removeClass(this._handled.getElement(), 'selected');
}

@@ -262,4 +356,5 @@

overlay.editing._hideToolbar();
overlay.editing._rotateBy(angle);
overlay.editing._scaleBy(scale);

@@ -277,7 +372,6 @@ /*

}
} else {
overlay.editing._scaleBy(scale);
}
}
overlay.fire('update');
},

@@ -335,3 +429,3 @@

},
_onHandleDrag: function() {

@@ -341,5 +435,6 @@ var overlay = this._handled,

newLatLng = this.getLatLng(),
angle = this._calculateAngle(formerLatLng, newLatLng);
overlay.editing._hideToolbar();
overlay.editing._rotateBy(angle);

@@ -460,10 +555,12 @@

height: 200,
crossOrigin: true
crossOrigin: true,
edgeMinWidth: 500,
},
initialize: function(url, options) {
this._url = url;
this._rotation = this.options.rotation;
this._toolArray = L.DistortableImage.EditToolbarDefaults;
this._url = url;
this._rotation = this.options.rotation;
L.setOptions(this, options);
L.setOptions(this, options);
},

@@ -484,4 +581,4 @@

/* Use provided corners if available */
if (this.options.corners) {
this._corners = this.options.corners;
if (this.options.corners) {
this._corners = this.options.corners;
if (map.options.zoomAnimation && L.Browser.any3d) {

@@ -491,4 +588,4 @@ map.on('zoomanim', this._animateZoom, this);

/* This reset happens before image load; it allows
* us to place the image on the map earlier with
/* This reset happens before image load; it allows
* us to place the image on the map earlier with
* "guessed" dimensions. */

@@ -498,3 +595,3 @@ this._reset();

/* Have to wait for the image to load because
/* Have to wait for the image to load because
* we need to access its width and height. */

@@ -505,3 +602,3 @@ L.DomEvent.on(this._image, 'load', function() {

/* Initialize default corners if not already set */
if (!this._corners) {
if (!this._corners) {
if (map.options.zoomAnimation && L.Browser.any3d) {

@@ -511,5 +608,5 @@ map.on('zoomanim', this._animateZoom, this);

}
}, this);
}, this);
this.fire('add');
this.fire('add');
},

@@ -531,2 +628,11 @@

_addTool: function(tool) {
this._toolArray.push(tool);
L.DistortableImage.EditToolbar = LeafletToolbar.Popup.extend({
options: {
actions: this._toolArray
}
});
},
_initImageDimensions: function() {

@@ -587,3 +693,24 @@ var map = this._map,

// fires a reset after all corner positions are updated instead of after each one (above). Use for translating
_updateCorners: function (latlngObj) {
var i = 0;
for (var k in latlngObj) {
this._corners[i] = latlngObj[k];
i += 1;
}
this._reset();
},
_updateCornersFromPoints: function (pointsObj) {
var map = this._map;
var i = 0;
for (var k in pointsObj) {
this._corners[i] = map.layerPointToLatLng(pointsObj[k]);
i += 1;
}
this._reset();
},
/* Copied from Leaflet v0.7 https://github.com/Leaflet/Leaflet/blob/66282f14bcb180ec87d9818d9f3c9f75afd01b30/src/dom/DomUtil.js#L189-L199 */

@@ -625,3 +752,3 @@ /* since L.DomUtil.getTranslateString() is deprecated in Leaflet v1.0 */

* Calculates the transform string that will be correct *at the end* of zooming.
* Leaflet then generates a CSS3 animation between the current transform and
* Leaflet then generates a CSS3 animation between the current transform and
* future transform which makes the transition appear smooth.

@@ -635,12 +762,12 @@ */

},
transformMatrix = this._calculateProjectiveTransform(latLngToNewLayerPoint),
topLeft = latLngToNewLayerPoint(this._corners[0]),
warp = L.DomUtil.getMatrixString(transformMatrix),
translation = this._getTranslateString(topLeft);
/* See L.DomUtil.setPosition. Mainly for the purposes of L.Draggable. */
image._leaflet_pos = topLeft;
if (!L.Browser.gecko) {

@@ -674,8 +801,13 @@ image.style[L.DomUtil.TRANSFORM] = [translation, warp].join(' ');

// Use for translation calculations - for translation the delta for 1 corner applies to all 4
_calcCornerPointDelta: function () {
return this._dragStartPoints[0].subtract(this._dragPoints[0]);
},
_calculateProjectiveTransform: function(latLngToCartesian) {
/* Setting reasonable but made-up image defaults
* allow us to place images on the map before
/* Setting reasonable but made-up image defaults
* allow us to place images on the map before
* they've finished downloading. */
var offset = latLngToCartesian(this._corners[0]),
w = this._image.offsetWidth || 500,
w = this._image.offsetWidth || 500,
h = this._image.offsetHeight || 375,

@@ -688,3 +820,3 @@ c = [],

}
/*

@@ -707,2 +839,184 @@ * This matrix describes the action of the CSS transform on each corner of the image.

L.distortableImageOverlay = function(id, options) {
return new L.DistortableImageOverlay(id, options);
};
L.DistortableCollection = L.FeatureGroup.extend({
include: L.Mixin.Events,
onAdd: function(map) {
L.FeatureGroup.prototype.onAdd.call(this, map);
this._map = map;
L.DomEvent.on(document, "keydown", this._onKeyDown, this);
L.DomEvent.on(map, "click", this._deselectAll, this);
/**
* the box zoom override works, but there is a bug involving click event propogation.
* keeping uncommented for now so that it isn't used as a multi-select mechanism
*/
// L.DomEvent.on(map, "boxzoomend", this._addSelections, this);
this.eachLayer(function(layer) {
L.DomEvent.on(layer._image, 'mousedown', this._deselectOthers, this);
L.DomEvent.on(layer, "dragstart", this._dragStartMultiple, this);
L.DomEvent.on(layer, "drag", this._dragMultiple, this);
}, this);
},
onRemove: function() {
var map = this._map;
L.DomEvent.off(document, "keydown", this._onKeyDown, this);
L.DomEvent.off(map, "click", this._deselectAll, this);
// L.DomEvent.off(map, "boxzoomend", this._addSelections, this);
this.eachLayer(function(layer) {
L.DomEvent.off(layer._image, 'mousedown', this._deselectOthers, this);
L.DomEvent.off(layer, "dragstart", this._dragStartMultiple, this);
L.DomEvent.off(layer, "drag", this._dragMultiple, this);
}, this);
},
isSelected: function (overlay) {
return L.DomUtil.hasClass(overlay.getElement(), "selected");
},
_toggleMultiSelect: function (event, edit) {
if (edit._mode === 'lock') { return; }
if (event.metaKey || event.ctrlKey) {
L.DomUtil.toggleClass(event.target, 'selected');
}
},
_deselectOthers: function(event) {
this.eachLayer(function (layer) {
var edit = layer.editing;
if (layer._image !== event.target) {
edit._hideMarkers();
edit._hideToolbar();
} else {
edit._showMarkers();
this._toggleMultiSelect(event, edit);
}
}, this);
},
_addSelections: function(e) {
var box = e.boxZoomBounds,
i = 0;
this.eachLayer(function(layer) {
var edit = layer.editing;
if (edit.toolbar) { edit._hideToolbar(); }
for (i = 0; i < 4; i++) {
if (box.contains(layer.getCorners()[i]) && edit._mode !== "lock") {
L.DomUtil.addClass(layer.getElement(), "selected");
break;
}
}
});
},
_onKeyDown: function (e) {
if (e.key === 'Escape') {
this._deselectAll();
}
},
_dragStartMultiple: function(event) {
var overlay = event.target,
i;
if (!this.isSelected(overlay)) { return; }
this.eachLayer(function(layer) {
for (i = 0; i < 4; i++) {
if (layer !== overlay) {
layer.editing._hideToolbar();
}
layer._dragStartPoints[i] = layer._map.latLngToLayerPoint(
layer.getCorners()[i]
);
}
});
},
_dragMultiple: function(event) {
var overlay = event.target,
map = this._map,
i;
if (!this.isSelected(overlay)) { return; }
overlay._dragPoints = {};
for (i = 0; i < 4; i++) {
overlay._dragPoints[i] = map.latLngToLayerPoint(overlay.getCorners()[i]);
}
var cpd = overlay._calcCornerPointDelta();
this._updateCollectionFromPoints(cpd, overlay);
},
_deselectAll: function() {
this.eachLayer(function(layer) {
var edit = layer.editing;
L.DomUtil.removeClass(layer.getElement(), "selected");
if (edit.toolbar) { edit._hideToolbar(); }
edit._hideMarkers();
});
},
/**
* images in 'lock' mode are included in this feature group collection for functionalities
* such as export, but are filtered out for editing / dragging here
*/
_calcCollectionFromPoints: function(cpd, overlay) {
var layersToMove = [],
p = new L.Transformation(1, -cpd.x, 1, -cpd.y);
this.eachLayer(function(layer) {
if (
layer !== overlay &&
layer.editing._mode !== "lock" &&
this.isSelected(layer)
) {
layer._cpd = {};
layer._cpd.val0 = p.transform(layer._dragStartPoints[0]);
layer._cpd.val1 = p.transform(layer._dragStartPoints[1]);
layer._cpd.val2 = p.transform(layer._dragStartPoints[2]);
layer._cpd.val3 = p.transform(layer._dragStartPoints[3]);
layersToMove.push(layer);
}
}, this);
return layersToMove;
},
/**
* cpd === cornerPointDelta
*/
_updateCollectionFromPoints: function(cpd, overlay) {
var layersToMove = this._calcCollectionFromPoints(
cpd,
overlay
);
layersToMove.forEach(function(layer) {
layer._updateCornersFromPoints(layer._cpd);
layer.fire("update");
}, this);
}
});
L.DistortableImage = L.DistortableImage || {};

@@ -720,6 +1034,6 @@

ToggleTransparency = EditOverlayAction.extend({
options: { toolbarIcon: {
options: { toolbarIcon: {
html: '<span class="fa fa-adjust"></span>',
tooltip: 'Toggle Image Transparency',
title: 'Toggle Image Transparency'
title: 'Toggle Image Transparency'
}},

@@ -736,3 +1050,3 @@

ToggleOutline = EditOverlayAction.extend({
options: { toolbarIcon: {
options: { toolbarIcon: {
html: '<span class="fa fa-square-o"></span>',

@@ -752,3 +1066,3 @@ tooltip: 'Toggle Image Outline',

RemoveOverlay = EditOverlayAction.extend({
options: { toolbarIcon: {
options: { toolbarIcon: {
html: '<span class="fa fa-trash"></span>',

@@ -772,3 +1086,3 @@ tooltip: 'Delete image',

tooltip: 'Lock / Unlock editing',
title: 'Lock / Unlock editing'
title: 'Lock / Unlock editing'
}},

@@ -792,3 +1106,3 @@

tooltip: 'Rotate',
title: 'Rotate'
title: 'Rotate'
};

@@ -816,3 +1130,3 @@

},
addHooks: function ()

@@ -823,6 +1137,39 @@ {

editing._toggleExport();
this.disable();
this.disable();
}
});
}),
ToggleOrder = EditOverlayAction.extend({
options: {
toolbarIcon: {
html: '<span class="fa fa-sort"></span>',
tooltip: 'Change order',
title: 'Toggle order'
}
},
addHooks: function ()
{
var editing = this._overlay.editing;
editing._toggleOrder();
this.disable();
}
}),
EnableEXIF = EditOverlayAction.extend({
options: {
toolbarIcon: {
html: '<span class="fa fa-compass"></span>',
tooltip: "Enable EXIF",
title: "Geocode Image"
}
},
addHooks: function() {
var image = this._overlay._image;
EXIF.getData(image, L.EXIF(image));
}
});
L.DistortableImage.EditToolbar = LeafletToolbar.Popup.extend({

@@ -836,3 +1183,5 @@ options: {

ToggleRotateDistort,
ToggleExport
ToggleExport,
EnableEXIF,
ToggleOrder
]

@@ -849,13 +1198,16 @@ }

keymap: {
8: '_removeOverlay', // backspace windows / delete mac
46: '_removeOverlay', // delete windows / delete + fn mac
20: '_toggleRotate', // CAPS
27: '_deselect', // esc
68: '_toggleRotateDistort', // d
69: '_toggleIsolate', // e
73: '_toggleIsolate', // i
74: '_sendUp', // j
75: '_sendDown', // k
76: '_toggleLock', // l
79: '_toggleOutline', // o
82: '_toggleRotateDistort', // r
46: "_removeOverlay", // delete windows / delete + fn mac
8: "_removeOverlay", // backspace windows / delete mac
83: '_toggleScale', // s
84: '_toggleTransparency', // t
20: '_toggleRotate' // CAPS
}

@@ -866,2 +1218,3 @@ },

this._overlay = overlay;
this._toggledImage = false;

@@ -874,3 +1227,3 @@ /* Interaction modes. */

/* Run on image seletion. */
/* Run on image selection. */
addHooks: function() {

@@ -881,5 +1234,2 @@ var overlay = this._overlay,

/* bring the selected image into view */
overlay.bringToFront();
this._lockHandles = new L.LayerGroup();

@@ -918,3 +1268,3 @@ for (i = 0; i < 4; i++) {

if (this._mode === 'lock') {
if (this._mode === 'lock') {
map.addLayer(this._lockHandles);

@@ -924,8 +1274,20 @@ } else {

map.addLayer(this._distortHandles);
this._distortHandles.eachLayer(function (layer) {
layer.setOpacity(0);
layer.dragging.disable();
layer.options.draggable = false;
});
this._enableDragging();
}
//overlay.on('click', this._showToolbar, this);
L.DomEvent.on(overlay._image, 'click', this._showToolbar, this);
this._overlay._dragStartPoints = {
0: new L.point(0, 0),
1: new L.point(0, 0),
2: new L.point(0, 0),
3: new L.point(0, 0)
};
L.DomEvent.on(map, "click", this._deselect, this);
L.DomEvent.on(overlay._image, 'click', this._select, this);
/* Enable hotkeys. */

@@ -935,6 +1297,5 @@ L.DomEvent.on(window, 'keydown', this._onKeyDown, this);

overlay.fire('select');
},
/* Run on image deseletion. */
/* Run on image deselection. */
removeHooks: function() {

@@ -944,11 +1305,12 @@ var overlay = this._overlay,

// L.DomEvent.off(window, 'keydown', this._onKeyDown, this);
L.DomEvent.off(map, "click", this._deselect, this);
L.DomEvent.off(overlay._image, 'click', this._select, this);
L.DomEvent.off(overlay._image, 'click', this._showToolbar, this);
// First, check if dragging exists;
// it may be off due to locking
// First, check if dragging exists - it may be off due to locking
if (this.dragging) { this.dragging.disable(); }
delete this.dragging;
if (this.toolbar) { this._hideToolbar(); }
if (this.editing) { this.editing.disable(); }
map.removeLayer(this._handles[this._mode]);

@@ -964,5 +1326,4 @@

return window.confirm("Are you sure you want to delete?");
},
},
_rotateBy: function(angle) {

@@ -1010,4 +1371,7 @@ var overlay = this._overlay,

/* Hide toolbars while dragging; click will re-show it */
this.dragging.on('dragstart', this._hideToolbar, this);
/* Hide toolbars and markers while dragging; click will re-show it */
this.dragging.on('dragstart', function () {
overlay.fire('dragstart');
this._hideToolbar();
}, this);

@@ -1031,2 +1395,3 @@ /*

overlay.fire('update');
overlay.fire('drag');

@@ -1042,3 +1407,3 @@ this.fire('drag');

if (handlerName !== undefined && this._overlay.options.suppressToolbar !== true) {
this[handlerName].call(this);
this[handlerName].call(this);
}

@@ -1063,5 +1428,3 @@ },

map.removeLayer(this._handles[this._mode]);
this._mode = 'scale';
map.addLayer(this._handles[this._mode]);

@@ -1074,5 +1437,3 @@ },

map.removeLayer(this._handles[this._mode]);
this._mode = 'rotateStandalone';
map.addLayer(this._handles[this._mode]);

@@ -1106,2 +1467,10 @@ },

_sendUp: function() {
this._overlay.bringToFront();
},
_sendDown: function() {
this._overlay.bringToBack();
},
_toggleLock: function() {

@@ -1124,2 +1493,14 @@ var map = this._overlay._map;

_select: function (event) {
this._showToolbar(event);
this._showMarkers();
L.DomEvent.stopPropagation(event);
},
_deselect: function (event) {
this._hideToolbar(event);
this._hideMarkers();
},
_hideToolbar: function() {

@@ -1133,5 +1514,27 @@ var map = this._overlay._map;

_showMarkers: function() {
if (this._mode === 'lock') { return; }
this._distortHandles.eachLayer(function (layer) {
layer.setOpacity(1);
layer.dragging.enable();
layer.options.draggable = true;
});
},
_hideMarkers: function() {
this._distortHandles.eachLayer(function (layer) {
var drag = layer.dragging,
opts = layer.options;
layer.setOpacity(0);
if (drag) { drag.disable(); }
if (opts.draggable) { opts.draggable = false; }
});
},
// TODO: toolbar for multiple image selection
_showToolbar: function(event) {
var overlay = this._overlay,
target = event.target,
target = event.target,
map = overlay._map;

@@ -1141,15 +1544,16 @@

this._hideToolbar();
var point;
if (event.containerPoint) { point = event.containerPoint; }
else { point = target._leaflet_pos; }
var raised_point = map.containerPointToLatLng(new L.Point(point.x,point.y-20));
raised_point.lng = overlay.getCenter().lng;
if (this._overlay.options.suppressToolbar !== true) {
this.toolbar = new L.DistortableImage.EditToolbar(raised_point).addTo(map, overlay);
overlay.fire('toolbar:created');
this.toolbar = new L.DistortableImage.EditToolbar(raised_point).addTo(map, overlay);
overlay.fire('toolbar:created');
}
},
L.DomEvent.stopPropagation(event);
},
_removeOverlay: function () {

@@ -1160,2 +1564,3 @@ var overlay = this._overlay;

if (choice) {
this._hideToolbar();
overlay._map.removeLayer(overlay);

@@ -1166,3 +1571,15 @@ overlay.fire('delete');

}
},
},
// compare this to using overlay zIndex
_toggleOrder: function () {
if (this._toggledImage) {
this._overlay.bringToFront();
this._toggledImage = false;
}
else {
this._overlay.bringToBack();
this._toggledImage = true;
}
},

@@ -1257,1 +1674,93 @@ // Based on https://github.com/publiclab/mapknitter/blob/8d94132c81b3040ae0d0b4627e685ff75275b416/app/assets/javascripts/mapknitter/Map.js#L47-L82

});
L.Map.mergeOptions({ boxSelector: true, boxZoom: false });
// used for multiple image select. Temporarily disabled until click
// propagation issue is fixed
L.Map.BoxSelectHandle = L.Map.BoxZoom.extend({
initialize: function (map) {
this._map = map;
this._container = map._container;
this._pane = map._panes.overlayPane;
},
addHooks: function () {
L.DomEvent.on(this._container, 'mousedown', this._onMouseDown, this);
},
removeHooks: function () {
L.DomEvent.off(this._container, 'mousedown', this._onMouseDown, this);
},
_onMouseDown: function (e) {
if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
L.DomUtil.disableTextSelection();
L.DomUtil.disableImageDrag();
this._startLayerPoint = this._map.mouseEventToLayerPoint(e);
this._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._pane);
L.DomUtil.setPosition(this._box, this._startLayerPoint);
this._container.style.cursor = 'crosshair';
L.DomEvent
.on(document, 'mousemove', this._onMouseMove, this)
.on(document, 'mouseup', this._onMouseUp, this)
.preventDefault(e);
this._map.fire('boxzoomstart');
},
_onMouseMove: function (e) {
var startPoint = this._startLayerPoint,
box = this._box,
layerPoint = this._map.mouseEventToLayerPoint(e),
offset = layerPoint.subtract(startPoint),
newPos = new L.Point(
Math.min(layerPoint.x, startPoint.x),
Math.min(layerPoint.y, startPoint.y));
L.DomUtil.setPosition(box, newPos);
box.style.width = (Math.max(0, Math.abs(offset.x) - 4)) + 'px';
box.style.height = (Math.max(0, Math.abs(offset.y) - 4)) + 'px';
},
_onMouseUp: function (e) {
var map = this._map,
layerPoint = map.mouseEventToLayerPoint(e);
if (this._startLayerPoint.equals(layerPoint)) { return; }
this._boxBounds = new L.LatLngBounds(
map.layerPointToLatLng(this._startLayerPoint),
map.layerPointToLatLng(layerPoint));
this._finish();
map.fire('boxzoomend', { boxZoomBounds: this._boxBounds });
// this._finish();
},
_finish: function () {
$(this._map.boxSelector._box).remove();
// L.DomUtil.remove(this._box);
// L.DomUtil.remove(this._map.boxSelector);
this._container.style.cursor = '';
L.DomUtil.enableTextSelection();
L.DomUtil.enableImageDrag();
L.DomEvent
.off(document, 'mousemove', this._onMouseMove)
.off(document, 'mouseup', this._onMouseUp);
},
});
L.Map.addInitHook('addHandler', 'boxSelector', L.Map.BoxSelectHandle);
module.exports = function(grunt) {
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
// require('exif-js');

@@ -31,2 +32,4 @@ grunt.initConfig({

warpWebGl: false,
EXIF: false,
alert: false,

@@ -81,2 +84,3 @@ // Mocha

'src/util/*.js',
'src/edit/getEXIFdata.js',
'src/edit/EditHandle.js',

@@ -89,4 +93,6 @@ 'src/edit/LockHandle.js',

'src/DistortableImageOverlay.js',
'src/DistortableCollection.js',
'src/edit/DistortableImage.EditToolbar.js',
'src/edit/DistortableImage.Edit.js',
'src/edit/BoxSelectHandle.js'
],

@@ -93,0 +99,0 @@ dest: 'dist/leaflet.distortableimage.js',

3

package.json
{
"name": "leaflet-distortableimage",
"version": "0.3.0",
"version": "0.4.0",
"description": "Leaflet plugin enabling image overlays to be distorted, stretched, and warped (built for Public Lab's MapKnitter: http://publiclab.org).",

@@ -36,2 +36,3 @@ "scripts": {

"chai": "^4.1.2",
"exif-js": "^2.3.0",
"font-awesome": "^4.2.0",

@@ -38,0 +39,0 @@ "glfx": "0.0.4",

@@ -1,2 +0,2 @@

Leaflet.DistortableImage
Leaflet.DistortableImage
===================

@@ -6,14 +6,14 @@

A Leaflet extension to distort images -- "rubbersheeting" -- for the [MapKnitter.org](http://mapknitter.org) ([src](https://github.com/publiclab/mapknitter)) image georectification service by [Public Lab](http://publiclab.org). Leaflet.DistortableImage allows for perspectival distortions of images, client-side, using CSS3 transformations in the DOM.
A Leaflet extension to distort images -- "rubbersheeting" -- for the [MapKnitter.org](http://mapknitter.org) ([src](https://github.com/publiclab/mapknitter)) image georectification service by [Public Lab](http://publiclab.org). Leaflet.DistortableImage allows for perspectival distortions of images, client-side, using CSS3 transformations in the DOM.
Advantages include:
* it can handle over 100 images smoothly, even on a smartphone.
* images can be right-clicked and downloaded individually in their original state
* It can handle over 100 images smoothly, even on a smartphone.
* Images can be right-clicked and downloaded individually in their original state
* CSS3 transforms are GPU-accelerated in most (all?) browsers, for a very smooth UI
* no need to server-side generate raster GeoTiffs, tilesets, etc in order to view distorted imagery layers
* images use DOM event handling for real-time distortion
* [full resolution download option](https://github.com/publiclab/Leaflet.DistortableImage/pull/100) for large images, using WebGL acceleration
* No need to server-side generate raster GeoTiffs, tilesets, etc. in order to view distorted imagery layers
* Images use DOM event handling for real-time distortion
* [Full resolution download option](https://github.com/publiclab/Leaflet.DistortableImage/pull/100) for large images, using WebGL acceleration
[Download as zip](https://github.com/publiclab/Leaflet.DistortableImage/releases) or clone to get a copy of the repo.
[Download as zip](https://github.com/publiclab/Leaflet.DistortableImage/releases) or clone the repo to get a local copy.

@@ -38,7 +38,9 @@ This plugin has basic functionality, and is in production as part of MapKnitter, but there are [plenty of outstanding issues to resolve](https://github.com/publiclab/Leaflet.DistortableImage/issues). Please consider helping out!

## Usage
## Basic Usage
The most simple implementation to get started:
```js
// basic Leaflet map setup
map = new L.map('map').setView([51.505, -0.09], 13);
map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('https://{s}.tiles.mapbox.com/v3/anishshah101.ipm9j6em/{z}/{x}/{y}.png', {

@@ -53,3 +55,3 @@ maxZoom: 18,

// create an image
img = new L.DistortableImageOverlay(
img = L.distortableImageOverlay(
'example.png', {

@@ -62,7 +64,7 @@ corners: [

],
fullResolutionSrc: 'large.jpg' // optionally pass in a higher resolution image to use in full-res exporting
}
).addTo(map);
L.DomEvent.on(img._image, 'load', img.editing.enable, img.editing); // enable editing
// enable editing
L.DomEvent.on(img._image, 'load', img.editing.enable, img.editing);

@@ -78,20 +80,16 @@ ```

<script src="../node_modules/webgl-distort/dist/webgl-distort.js"></script>
<script src="../node_modules/glfx-js/dist/glfx.js"></script>
<script src="../node_modules/glfx/glfx.js"></script>
```
## Usage
When instantiating a Distortable Image, pass in a `fullResolutionSrc` option set to the url of the higher resolution image. This image will be used in full-res exporting.
```js
// basic Leaflet map setup
map = new L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('https://{s}.tiles.mapbox.com/v3/anishshah101.ipm9j6em/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
id: 'examples.map-i86knfo3'
}).addTo(map);
// create an image
img = new L.DistortableImageOverlay(
// create basic map setup from above
// create an image - note the optional
// fullResolutionSrc option is now passed in
img = L.distortableImageOverlay(
'example.png', {

@@ -104,12 +102,69 @@ corners: [

],
fullResolutionSrc: 'large.jpg' // optionally pass in a higher resolution image to use in full-res exporting
fullResolutionSrc: 'large.jpg'
}
).addTo(map);
L.DomEvent.on(img._image, 'load', img.editing.enable, img.editing); // enable editing
L.DomEvent.on(img._image, 'load', img.editing.enable, img.editing);
```
****
## Multiple Images
To test the multi-image interface, open `select.html`. Currently it supports multiple image selection and translations; image distortions still use the single-image interface.
- Multiple images can be selected using <kbd>cmd</kbd> + `click` to toggle individual image selection.
- Click on the map or hit the <kbd>esc</kbd> key to quickly deselect all images.
Our `DistortableCollection` class allows working with multiple images simultaneously. Say we instantiated 3 images, saved them to the variables `img`, `img2`, and `img3`, and enabled editing on all of them. To access the UI and functionalities available in the multiple image interface, pass them to the collection class:
```js
// OPTION 1: Pass in images immediately
new L.DistortableCollection([img, img2, img3]).addTo(map);
// OPTION 2: Instantiate an empty collection and pass in images later
var imageFeatureGroup = new L.DistortableCollection().addTo(map);
imageFeatureGroup.addLayer(img);
imageFeatureGroup.addLayer(img2);
imageFeatureGroup.addLayer(img3);
```
## Image-ordering
For multiple images, we've also added a `ToggleOrder` action, that switches overlapping images back and forth into view by employing [`bringToFront()`](https://leafletjs.com/reference-1.4.0.html#popup-bringtofront) and [`bringToBack()`](https://leafletjs.com/reference-1.4.0.html#popup-bringtoback) from the Leaflet API.
```js
ToggleOrder = EditOverlayAction.extend({
options: {
toolbarIcon: {
html: '<span class="fa fa-sort"></span>',
tooltip: 'Change order',
title: 'Toggle order'
}
},
addHooks: function ()
{
var editing = this._overlay.editing;
editing._toggleOrder(); // toggles images into view
this.disable();
}
});
```
### Corners
The corners are stored in `img._corners` as `L.latLng` objects, so after instantiating the image and moving it around, you can always access them like this:
```js
img = L.distortableImageOverlay(...);
img.addTo(map);
// move the image around
JSON.stringify(img._corners)
=> "[{"lat":51.52,"lng":-0.1},{"lat":51.52,"lng":-0.14},{"lat":51.5,"lng":-0.1},{"lat":51.5,"lng":-0.14}]"
```
## Setup

@@ -136,1 +191,2 @@

Many more at https://github.com/publiclab/Leaflet.DistortableImage/graphs/contributors


@@ -7,10 +7,12 @@ L.DistortableImageOverlay = L.ImageOverlay.extend({

height: 200,
crossOrigin: true
crossOrigin: true,
edgeMinWidth: 500,
},
initialize: function(url, options) {
this._url = url;
this._rotation = this.options.rotation;
this._toolArray = L.DistortableImage.EditToolbarDefaults;
this._url = url;
this._rotation = this.options.rotation;
L.setOptions(this, options);
L.setOptions(this, options);
},

@@ -31,4 +33,4 @@

/* Use provided corners if available */
if (this.options.corners) {
this._corners = this.options.corners;
if (this.options.corners) {
this._corners = this.options.corners;
if (map.options.zoomAnimation && L.Browser.any3d) {

@@ -38,4 +40,4 @@ map.on('zoomanim', this._animateZoom, this);

/* This reset happens before image load; it allows
* us to place the image on the map earlier with
/* This reset happens before image load; it allows
* us to place the image on the map earlier with
* "guessed" dimensions. */

@@ -45,3 +47,3 @@ this._reset();

/* Have to wait for the image to load because
/* Have to wait for the image to load because
* we need to access its width and height. */

@@ -52,3 +54,3 @@ L.DomEvent.on(this._image, 'load', function() {

/* Initialize default corners if not already set */
if (!this._corners) {
if (!this._corners) {
if (map.options.zoomAnimation && L.Browser.any3d) {

@@ -58,5 +60,5 @@ map.on('zoomanim', this._animateZoom, this);

}
}, this);
}, this);
this.fire('add');
this.fire('add');
},

@@ -78,2 +80,11 @@

_addTool: function(tool) {
this._toolArray.push(tool);
L.DistortableImage.EditToolbar = LeafletToolbar.Popup.extend({
options: {
actions: this._toolArray
}
});
},
_initImageDimensions: function() {

@@ -134,3 +145,24 @@ var map = this._map,

// fires a reset after all corner positions are updated instead of after each one (above). Use for translating
_updateCorners: function (latlngObj) {
var i = 0;
for (var k in latlngObj) {
this._corners[i] = latlngObj[k];
i += 1;
}
this._reset();
},
_updateCornersFromPoints: function (pointsObj) {
var map = this._map;
var i = 0;
for (var k in pointsObj) {
this._corners[i] = map.layerPointToLatLng(pointsObj[k]);
i += 1;
}
this._reset();
},
/* Copied from Leaflet v0.7 https://github.com/Leaflet/Leaflet/blob/66282f14bcb180ec87d9818d9f3c9f75afd01b30/src/dom/DomUtil.js#L189-L199 */

@@ -172,3 +204,3 @@ /* since L.DomUtil.getTranslateString() is deprecated in Leaflet v1.0 */

* Calculates the transform string that will be correct *at the end* of zooming.
* Leaflet then generates a CSS3 animation between the current transform and
* Leaflet then generates a CSS3 animation between the current transform and
* future transform which makes the transition appear smooth.

@@ -182,12 +214,12 @@ */

},
transformMatrix = this._calculateProjectiveTransform(latLngToNewLayerPoint),
topLeft = latLngToNewLayerPoint(this._corners[0]),
warp = L.DomUtil.getMatrixString(transformMatrix),
translation = this._getTranslateString(topLeft);
/* See L.DomUtil.setPosition. Mainly for the purposes of L.Draggable. */
image._leaflet_pos = topLeft;
if (!L.Browser.gecko) {

@@ -221,8 +253,13 @@ image.style[L.DomUtil.TRANSFORM] = [translation, warp].join(' ');

// Use for translation calculations - for translation the delta for 1 corner applies to all 4
_calcCornerPointDelta: function () {
return this._dragStartPoints[0].subtract(this._dragPoints[0]);
},
_calculateProjectiveTransform: function(latLngToCartesian) {
/* Setting reasonable but made-up image defaults
* allow us to place images on the map before
/* Setting reasonable but made-up image defaults
* allow us to place images on the map before
* they've finished downloading. */
var offset = latLngToCartesian(this._corners[0]),
w = this._image.offsetWidth || 500,
w = this._image.offsetWidth || 500,
h = this._image.offsetHeight || 375,

@@ -235,3 +272,3 @@ c = [],

}
/*

@@ -253,1 +290,8 @@ * This matrix describes the action of the CSS transform on each corner of the image.

});
L.distortableImageOverlay = function(id, options) {
return new L.DistortableImageOverlay(id, options);
};

@@ -8,13 +8,16 @@ L.DistortableImage = L.DistortableImage || {};

keymap: {
8: '_removeOverlay', // backspace windows / delete mac
46: '_removeOverlay', // delete windows / delete + fn mac
20: '_toggleRotate', // CAPS
27: '_deselect', // esc
68: '_toggleRotateDistort', // d
69: '_toggleIsolate', // e
73: '_toggleIsolate', // i
74: '_sendUp', // j
75: '_sendDown', // k
76: '_toggleLock', // l
79: '_toggleOutline', // o
82: '_toggleRotateDistort', // r
46: "_removeOverlay", // delete windows / delete + fn mac
8: "_removeOverlay", // backspace windows / delete mac
83: '_toggleScale', // s
84: '_toggleTransparency', // t
20: '_toggleRotate' // CAPS
}

@@ -25,2 +28,3 @@ },

this._overlay = overlay;
this._toggledImage = false;

@@ -33,3 +37,3 @@ /* Interaction modes. */

/* Run on image seletion. */
/* Run on image selection. */
addHooks: function() {

@@ -40,5 +44,2 @@ var overlay = this._overlay,

/* bring the selected image into view */
overlay.bringToFront();
this._lockHandles = new L.LayerGroup();

@@ -77,3 +78,3 @@ for (i = 0; i < 4; i++) {

if (this._mode === 'lock') {
if (this._mode === 'lock') {
map.addLayer(this._lockHandles);

@@ -83,8 +84,20 @@ } else {

map.addLayer(this._distortHandles);
this._distortHandles.eachLayer(function (layer) {
layer.setOpacity(0);
layer.dragging.disable();
layer.options.draggable = false;
});
this._enableDragging();
}
//overlay.on('click', this._showToolbar, this);
L.DomEvent.on(overlay._image, 'click', this._showToolbar, this);
this._overlay._dragStartPoints = {
0: new L.point(0, 0),
1: new L.point(0, 0),
2: new L.point(0, 0),
3: new L.point(0, 0)
};
L.DomEvent.on(map, "click", this._deselect, this);
L.DomEvent.on(overlay._image, 'click', this._select, this);
/* Enable hotkeys. */

@@ -94,6 +107,5 @@ L.DomEvent.on(window, 'keydown', this._onKeyDown, this);

overlay.fire('select');
},
/* Run on image deseletion. */
/* Run on image deselection. */
removeHooks: function() {

@@ -103,11 +115,12 @@ var overlay = this._overlay,

// L.DomEvent.off(window, 'keydown', this._onKeyDown, this);
L.DomEvent.off(map, "click", this._deselect, this);
L.DomEvent.off(overlay._image, 'click', this._select, this);
L.DomEvent.off(overlay._image, 'click', this._showToolbar, this);
// First, check if dragging exists;
// it may be off due to locking
// First, check if dragging exists - it may be off due to locking
if (this.dragging) { this.dragging.disable(); }
delete this.dragging;
if (this.toolbar) { this._hideToolbar(); }
if (this.editing) { this.editing.disable(); }
map.removeLayer(this._handles[this._mode]);

@@ -123,5 +136,4 @@

return window.confirm("Are you sure you want to delete?");
},
},
_rotateBy: function(angle) {

@@ -169,4 +181,7 @@ var overlay = this._overlay,

/* Hide toolbars while dragging; click will re-show it */
this.dragging.on('dragstart', this._hideToolbar, this);
/* Hide toolbars and markers while dragging; click will re-show it */
this.dragging.on('dragstart', function () {
overlay.fire('dragstart');
this._hideToolbar();
}, this);

@@ -190,2 +205,3 @@ /*

overlay.fire('update');
overlay.fire('drag');

@@ -201,3 +217,3 @@ this.fire('drag');

if (handlerName !== undefined && this._overlay.options.suppressToolbar !== true) {
this[handlerName].call(this);
this[handlerName].call(this);
}

@@ -222,5 +238,3 @@ },

map.removeLayer(this._handles[this._mode]);
this._mode = 'scale';
map.addLayer(this._handles[this._mode]);

@@ -233,5 +247,3 @@ },

map.removeLayer(this._handles[this._mode]);
this._mode = 'rotateStandalone';
map.addLayer(this._handles[this._mode]);

@@ -265,2 +277,10 @@ },

_sendUp: function() {
this._overlay.bringToFront();
},
_sendDown: function() {
this._overlay.bringToBack();
},
_toggleLock: function() {

@@ -283,2 +303,14 @@ var map = this._overlay._map;

_select: function (event) {
this._showToolbar(event);
this._showMarkers();
L.DomEvent.stopPropagation(event);
},
_deselect: function (event) {
this._hideToolbar(event);
this._hideMarkers();
},
_hideToolbar: function() {

@@ -292,5 +324,27 @@ var map = this._overlay._map;

_showMarkers: function() {
if (this._mode === 'lock') { return; }
this._distortHandles.eachLayer(function (layer) {
layer.setOpacity(1);
layer.dragging.enable();
layer.options.draggable = true;
});
},
_hideMarkers: function() {
this._distortHandles.eachLayer(function (layer) {
var drag = layer.dragging,
opts = layer.options;
layer.setOpacity(0);
if (drag) { drag.disable(); }
if (opts.draggable) { opts.draggable = false; }
});
},
// TODO: toolbar for multiple image selection
_showToolbar: function(event) {
var overlay = this._overlay,
target = event.target,
target = event.target,
map = overlay._map;

@@ -300,15 +354,16 @@

this._hideToolbar();
var point;
if (event.containerPoint) { point = event.containerPoint; }
else { point = target._leaflet_pos; }
var raised_point = map.containerPointToLatLng(new L.Point(point.x,point.y-20));
raised_point.lng = overlay.getCenter().lng;
if (this._overlay.options.suppressToolbar !== true) {
this.toolbar = new L.DistortableImage.EditToolbar(raised_point).addTo(map, overlay);
overlay.fire('toolbar:created');
this.toolbar = new L.DistortableImage.EditToolbar(raised_point).addTo(map, overlay);
overlay.fire('toolbar:created');
}
},
L.DomEvent.stopPropagation(event);
},
_removeOverlay: function () {

@@ -319,2 +374,3 @@ var overlay = this._overlay;

if (choice) {
this._hideToolbar();
overlay._map.removeLayer(overlay);

@@ -325,3 +381,15 @@ overlay.fire('delete');

}
},
},
// compare this to using overlay zIndex
_toggleOrder: function () {
if (this._toggledImage) {
this._overlay.bringToFront();
this._toggledImage = false;
}
else {
this._overlay.bringToBack();
this._toggledImage = true;
}
},

@@ -415,2 +483,2 @@ // Based on https://github.com/publiclab/mapknitter/blob/8d94132c81b3040ae0d0b4627e685ff75275b416/app/assets/javascripts/mapknitter/Map.js#L47-L82

});
});
});

@@ -13,6 +13,6 @@ L.DistortableImage = L.DistortableImage || {};

ToggleTransparency = EditOverlayAction.extend({
options: { toolbarIcon: {
options: { toolbarIcon: {
html: '<span class="fa fa-adjust"></span>',
tooltip: 'Toggle Image Transparency',
title: 'Toggle Image Transparency'
title: 'Toggle Image Transparency'
}},

@@ -29,3 +29,3 @@

ToggleOutline = EditOverlayAction.extend({
options: { toolbarIcon: {
options: { toolbarIcon: {
html: '<span class="fa fa-square-o"></span>',

@@ -45,3 +45,3 @@ tooltip: 'Toggle Image Outline',

RemoveOverlay = EditOverlayAction.extend({
options: { toolbarIcon: {
options: { toolbarIcon: {
html: '<span class="fa fa-trash"></span>',

@@ -65,3 +65,3 @@ tooltip: 'Delete image',

tooltip: 'Lock / Unlock editing',
title: 'Lock / Unlock editing'
title: 'Lock / Unlock editing'
}},

@@ -85,3 +85,3 @@

tooltip: 'Rotate',
title: 'Rotate'
title: 'Rotate'
};

@@ -109,3 +109,3 @@

},
addHooks: function ()

@@ -116,6 +116,39 @@ {

editing._toggleExport();
this.disable();
this.disable();
}
});
}),
ToggleOrder = EditOverlayAction.extend({
options: {
toolbarIcon: {
html: '<span class="fa fa-sort"></span>',
tooltip: 'Change order',
title: 'Toggle order'
}
},
addHooks: function ()
{
var editing = this._overlay.editing;
editing._toggleOrder();
this.disable();
}
}),
EnableEXIF = EditOverlayAction.extend({
options: {
toolbarIcon: {
html: '<span class="fa fa-compass"></span>',
tooltip: "Enable EXIF",
title: "Geocode Image"
}
},
addHooks: function() {
var image = this._overlay._image;
EXIF.getData(image, L.EXIF(image));
}
});
L.DistortableImage.EditToolbar = LeafletToolbar.Popup.extend({

@@ -129,5 +162,7 @@ options: {

ToggleRotateDistort,
ToggleExport
ToggleExport,
EnableEXIF,
ToggleOrder
]
}
});
L.EditHandle = L.Marker.extend({
initialize: function(overlay, corner, options) {

@@ -3,0 +4,0 @@ var markerOptions,

@@ -17,4 +17,5 @@ L.LockHandle = L.EditHandle.extend({

this.setLatLng(this._handled._corners[this._corner]);
L.DomUtil.removeClass(this._handled.getElement(), 'selected');
}
});

@@ -19,4 +19,5 @@ L.RotateAndScaleHandle = L.EditHandle.extend({

overlay.editing._hideToolbar();
overlay.editing._rotateBy(angle);
overlay.editing._scaleBy(scale);

@@ -34,7 +35,6 @@ /*

}
} else {
overlay.editing._scaleBy(scale);
}
}
overlay.fire('update');
},

@@ -41,0 +41,0 @@

@@ -10,3 +10,3 @@ L.RotateHandle = L.EditHandle.extend({

},
_onHandleDrag: function() {

@@ -16,5 +16,6 @@ var overlay = this._handled,

newLatLng = this.getLatLng(),
angle = this._calculateAngle(formerLatLng, newLatLng);
overlay.editing._hideToolbar();
overlay.editing._rotateBy(angle);

@@ -21,0 +22,0 @@

@@ -33,3 +33,9 @@ L.DomUtil = L.extend(L.DomUtil, {

return open + rotateString + ')';
},
toggleClass: function(el, className) {
var c = className;
return this.hasClass(el, c) ? this.removeClass(el, c) : this.addClass(el, c);
}
});

@@ -36,2 +36,4 @@ // Karma configuration

"src/util/*.js",
"src/edit/getEXIFdata.js",
"src/edit/BoxSelectHandle.js",
"src/edit/EditHandle.js",

@@ -43,2 +45,3 @@ "src/edit/LockHandle.js",

"src/edit/ScaleHandle.js",
"src/DistortableCollection.js",
"src/DistortableImageOverlay.js",

@@ -48,6 +51,7 @@ "src/edit/DistortableImage.EditToolbar.js",

"test/SpecHelper.js",
"test/src/*Spec.js",
"test/src/**/*Spec.js"
],
// so that karma can serve examples/example.jpg
// so that karma can serve examples/example.png
proxies: {

@@ -54,0 +58,0 @@ "/examples/": "/base/examples/"

@@ -6,3 +6,3 @@ describe("L.DistortableImage.Edit", function() {

beforeEach(function(done) {
map = new L.Map(L.DomUtil.create('div', '', document.body)).setView([41.7896,-87.5996], 15);
map = L.map(L.DomUtil.create('div', '', document.body)).setView([41.7896,-87.5996], 15);

@@ -9,0 +9,0 @@ overlay = new L.DistortableImageOverlay('/examples/example.png', {

@@ -7,3 +7,3 @@ describe("L.RotateAndScaleHandle", function() {

beforeEach(function(done) {
map = new L.Map(L.DomUtil.create('div', '', document.body)).setView([41.7896,-87.5996], 15);
map = L.map(L.DomUtil.create('div', '', document.body)).setView([41.7896,-87.5996], 15);
distortable = new L.DistortableImageOverlay('/examples/example.png', {

@@ -24,2 +24,6 @@ corners: [

it.skip("Should not distort the image during scaling", function () {
});
describe("_calculateRotation", function() {

@@ -26,0 +30,0 @@ it("Should return 0 when given the same latlng twice.", function() {

@@ -7,3 +7,3 @@ describe("L.RotateHandle", function() {

beforeEach(function(done) {
map = new L.Map(L.DomUtil.create('div', '', document.body)).setView([41.7896,-87.5996], 15);
map = L.map(L.DomUtil.create('div', '', document.body)).setView([41.7896,-87.5996], 15);
distortable = new L.DistortableImageOverlay('/examples/example.jpg', {

@@ -10,0 +10,0 @@ corners: [

@@ -7,3 +7,3 @@ describe("L.ScaleHandle", function() {

beforeEach(function(done) {
map = new L.Map(L.DomUtil.create('div', '', document.body)).setView([41.7896,-87.5996], 15);
map = L.map(L.DomUtil.create('div', '', document.body)).setView([41.7896,-87.5996], 15);
distortable = new L.DistortableImageOverlay('/examples/example.jpg', {

@@ -10,0 +10,0 @@ corners: [

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc