Merge pull request #1311 from pierotofy/dropimageupload

Efficient camera markers
pull/1312/head
Piero Toffanin 2023-03-23 17:37:51 -04:00 zatwierdzone przez GitHub
commit 14c0a356fa
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
14 zmienionych plików z 567 dodań i 318 usunięć

Wyświetl plik

@ -26,7 +26,8 @@ import LayersControl from './LayersControl';
import update from 'immutability-helper';
import Utils from '../classes/Utils';
import '../vendor/leaflet/Leaflet.Ajax';
import '../vendor/leaflet/Leaflet.Awesome-markers';
import 'rbush';
import '../vendor/leaflet/leaflet-markers-canvas';
import { _ } from '../classes/gettext';
class Map extends React.Component {
@ -228,41 +229,45 @@ class Map extends React.Component {
// Add camera shots layer if available
if (meta.task && meta.task.camera_shots && !this.addedCameraShots){
const shotsLayer = new L.GeoJSON.AJAX(meta.task.camera_shots, {
style: function (feature) {
return {
opacity: 1,
fillOpacity: 0.7,
color: "#000000"
}
},
pointToLayer: function (feature, latlng) {
return new L.CircleMarker(latlng, {
color: '#3498db',
fillColor: '#3498db',
fillOpacity: 0.9,
radius: 10,
weight: 1
});
},
onEachFeature: function (feature, layer) {
if (feature.properties && feature.properties.filename) {
let root = null;
const lazyrender = () => {
if (!root) root = document.createElement("div");
ReactDOM.render(<ImagePopup task={meta.task} feature={feature}/>, root);
return root;
}
layer.bindPopup(L.popup(
{
lazyrender,
maxHeight: 450,
minWidth: 320
}));
}
}
var camIcon = L.icon({
iconUrl: "/static/app/js/icons/marker-camera.png",
iconSize: [41, 46],
iconAnchor: [17, 46],
});
const shotsLayer = new L.MarkersCanvas();
$.getJSON(meta.task.camera_shots)
.done((shots) => {
if (shots.type === 'FeatureCollection'){
let markers = [];
shots.features.forEach(s => {
let marker = L.marker(
[s.geometry.coordinates[1], s.geometry.coordinates[0]],
{ icon: camIcon }
);
markers.push(marker);
if (s.properties && s.properties.filename){
let root = null;
const lazyrender = () => {
if (!root) root = document.createElement("div");
ReactDOM.render(<ImagePopup task={meta.task} feature={s}/>, root);
return root;
}
marker.bindPopup(L.popup(
{
lazyrender,
maxHeight: 450,
minWidth: 320
}));
}
});
shotsLayer.addMarkers(markers, this.map);
}
});
shotsLayer[Symbol.for("meta")] = {name: name + " " + _("(Cameras)"), icon: "fa fa-camera fa-fw"};
this.setState(update(this.state, {
@ -274,44 +279,45 @@ class Map extends React.Component {
// Add ground control points layer if available
if (meta.task && meta.task.ground_control_points && !this.addedGroundControlPoints){
const gcpMarker = L.AwesomeMarkers.icon({
icon: 'dot-circle',
markerColor: 'blue',
prefix: 'fa'
const gcpIcon = L.icon({
iconUrl: "/static/app/js/icons/marker-gcp.png",
iconSize: [41, 46],
iconAnchor: [17, 46],
});
const gcpLayer = new L.MarkersCanvas();
$.getJSON(meta.task.ground_control_points)
.done((gcps) => {
if (gcps.type === 'FeatureCollection'){
let markers = [];
const gcpLayer = new L.GeoJSON.AJAX(meta.task.ground_control_points, {
style: function (feature) {
return {
opacity: 1,
fillOpacity: 0.7,
color: "#000000"
}
},
pointToLayer: function (feature, latlng) {
return new L.marker(latlng, {
icon: gcpMarker
});
},
onEachFeature: function (feature, layer) {
if (feature.properties && feature.properties.observations) {
// TODO!
let root = null;
const lazyrender = () => {
gcps.features.forEach(gcp => {
let marker = L.marker(
[gcp.geometry.coordinates[1], gcp.geometry.coordinates[0]],
{ icon: gcpIcon }
);
markers.push(marker);
if (gcp.properties && gcp.properties.observations){
let root = null;
const lazyrender = () => {
if (!root) root = document.createElement("div");
ReactDOM.render(<GCPPopup task={meta.task} feature={feature}/>, root);
ReactDOM.render(<GCPPopup task={meta.task} feature={gcp}/>, root);
return root;
}
}
layer.bindPopup(L.popup(
{
lazyrender,
maxHeight: 450,
minWidth: 320
}));
marker.bindPopup(L.popup(
{
lazyrender,
maxHeight: 450,
minWidth: 320
}));
}
});
gcpLayer.addMarkers(markers, this.map);
}
});
});
gcpLayer[Symbol.for("meta")] = {name: name + " " + _("(GCPs)"), icon: "far fa-dot-circle fa-fw"};
this.setState(update(this.state, {

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 5.0 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 6.0 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 14 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 30 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 7.8 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 535 B

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 40 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 65 KiB

Wyświetl plik

@ -1,127 +0,0 @@
/*
Leaflet.AwesomeMarkers, a plugin that adds colorful iconic markers for Leaflet, based on the Font Awesome icons
(c) 2012-2013, Lennard Voogdt
http://leafletjs.com
https://github.com/lvoogdt
*/
/*global L*/
import "./leaflet.awesome-markers.css";
(function (window, document, undefined) {
"use strict";
/*
* Leaflet.AwesomeMarkers assumes that you have already included the Leaflet library.
*/
L.AwesomeMarkers = {};
L.AwesomeMarkers.version = '2.0.1';
L.AwesomeMarkers.Icon = L.Icon.extend({
options: {
iconSize: [35, 45],
iconAnchor: [17, 42],
popupAnchor: [1, -32],
shadowAnchor: [10, 12],
shadowSize: [36, 16],
className: 'awesome-marker',
prefix: 'glyphicon',
spinClass: 'fa-spin',
extraClasses: '',
icon: 'home',
markerColor: 'blue',
iconColor: 'white'
},
initialize: function (options) {
options = L.Util.setOptions(this, options);
},
createIcon: function () {
var div = document.createElement('div'),
options = this.options;
if (options.icon) {
div.innerHTML = this._createInner();
}
if (options.bgPos) {
div.style.backgroundPosition =
(-options.bgPos.x) + 'px ' + (-options.bgPos.y) + 'px';
}
this._setIconStyles(div, 'icon-' + options.markerColor);
return div;
},
_createInner: function() {
var iconClass, iconSpinClass = "", iconColorClass = "", iconColorStyle = "", options = this.options;
if(options.icon.slice(0,options.prefix.length+1) === options.prefix + "-") {
iconClass = options.icon;
} else {
iconClass = options.prefix + "-" + options.icon;
}
if(options.spin && typeof options.spinClass === "string") {
iconSpinClass = options.spinClass;
}
if(options.iconColor) {
if(options.iconColor === 'white' || options.iconColor === 'black') {
iconColorClass = "icon-" + options.iconColor;
} else {
iconColorStyle = "style='color: " + options.iconColor + "' ";
}
}
return "<i " + iconColorStyle + "class='" + options.extraClasses + " " + options.prefix + " " + iconClass + " " + iconSpinClass + " " + iconColorClass + "'></i>";
},
_setIconStyles: function (img, name) {
var options = this.options,
size = L.point(options[name === 'shadow' ? 'shadowSize' : 'iconSize']),
anchor;
if (name === 'shadow') {
anchor = L.point(options.shadowAnchor || options.iconAnchor);
} else {
anchor = L.point(options.iconAnchor);
}
if (!anchor && size) {
anchor = size.divideBy(2, true);
}
img.className = 'awesome-marker-' + name + ' ' + options.className;
if (anchor) {
img.style.marginLeft = (-anchor.x) + 'px';
img.style.marginTop = (-anchor.y) + 'px';
}
if (size) {
img.style.width = size.x + 'px';
img.style.height = size.y + 'px';
}
},
createShadow: function () {
var div = document.createElement('div');
this._setIconStyles(div, 'shadow');
return div;
}
});
L.AwesomeMarkers.icon = function (options) {
return new L.AwesomeMarkers.Icon(options);
};
}(this, document));

Wyświetl plik

@ -1,124 +0,0 @@
/*
Author: L. Voogdt
License: MIT
Version: 1.0
*/
/* Marker setup */
.awesome-marker {
background: url('images/markers-soft.png') no-repeat 0 0;
width: 35px;
height: 46px;
position:absolute;
left:0;
top:0;
display: block;
text-align: center;
}
.awesome-marker-shadow {
background: url('images/markers-shadow.png') no-repeat 0 0;
width: 36px;
height: 16px;
}
/* Retina displays */
@media (min--moz-device-pixel-ratio: 1.5),(-o-min-device-pixel-ratio: 3/2),
(-webkit-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5),(min-resolution: 1.5dppx) {
.awesome-marker {
background-image: url('images/markers-soft@2x.png');
background-size: 720px 46px;
}
.awesome-marker-shadow {
background-image: url('images/markers-shadow@2x.png');
background-size: 35px 16px;
}
}
.awesome-marker i {
color: #333;
margin-top: 10px;
display: inline-block;
font-size: 14px;
}
.awesome-marker .icon-white {
color: #fff;
}
/* Colors */
.awesome-marker-icon-red {
background-position: 0 0;
}
.awesome-marker-icon-darkred {
background-position: -180px 0;
}
.awesome-marker-icon-lightred {
background-position: -360px 0;
}
.awesome-marker-icon-orange {
background-position: -36px 0;
}
.awesome-marker-icon-beige {
background-position: -396px 0;
}
.awesome-marker-icon-green {
background-position: -72px 0;
}
.awesome-marker-icon-darkgreen {
background-position: -252px 0;
}
.awesome-marker-icon-lightgreen {
background-position: -432px 0;
}
.awesome-marker-icon-blue {
background-position: -108px 0;
}
.awesome-marker-icon-darkblue {
background-position: -216px 0;
}
.awesome-marker-icon-lightblue {
background-position: -468px 0;
}
.awesome-marker-icon-purple {
background-position: -144px 0;
}
.awesome-marker-icon-darkpurple {
background-position: -288px 0;
}
.awesome-marker-icon-pink {
background-position: -504px 0;
}
.awesome-marker-icon-cadetblue {
background-position: -324px 0;
}
.awesome-marker-icon-white {
background-position: -574px 0;
}
.awesome-marker-icon-gray {
background-position: -648px 0;
}
.awesome-marker-icon-lightgray {
background-position: -612px 0;
}
.awesome-marker-icon-black {
background-position: -682px 0;
}

Wyświetl plik

@ -0,0 +1,493 @@
/*https://github.com/francoisromain/leaflet-markers-canvas/blob/master/licence.md*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('leaflet'), require('rbush')) :
typeof define === 'function' && define.amd ? define(['leaflet', 'rbush'], factory) :
(global = global || self, factory(global.L, global.RBush));
}(this, (function (L, RBush) { 'use strict';
L = L && Object.prototype.hasOwnProperty.call(L, 'default') ? L['default'] : L;
RBush = RBush && Object.prototype.hasOwnProperty.call(RBush, 'default') ? RBush['default'] : RBush;
var markersCanvas = {
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//
// private: properties
//
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
_map: null,
_canvas: null,
_context: null,
// leaflet markers (used to getBounds)
_markers: [],
// visible markers
_markersTree: null,
// every marker positions (even out of the canvas)
_positionsTree: null,
// icon images index
_icons: {},
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//
// public: global
//
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
addTo: function addTo(map) {
map.addLayer(this);
return this;
},
getBounds: function getBounds() {
var bounds = new L.LatLngBounds();
this._markers.forEach(function (marker) {
bounds.extend(marker.getLatLng());
});
return bounds;
},
redraw: function redraw() {
this._redraw(true);
},
clear: function clear() {
this._positionsTree = new RBush();
this._markersTree = new RBush();
this._markers = [];
this._redraw(true);
},
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//
// public: markers
//
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
addMarker: function addMarker(marker, map) {
var ref = this._addMarker(marker, map);
var markerBox = ref.markerBox;
var positionBox = ref.positionBox;
var isVisible = ref.isVisible;
if (markerBox && isVisible) {
this._markersTree.insert(markerBox);
}
if (positionBox) {
this._positionsTree.insert(positionBox);
}
},
// add multiple markers (better for rBush performance)
addMarkers: function addMarkers(markers, map) {
if (!this._markersTree) this._markersTree = new RBush();
if (!this._positionsTree) this._positionsTree = new RBush();
var this$1 = this;
var markerBoxes = [];
var positionBoxes = [];
markers.forEach(function (marker) {
var ref = this$1._addMarker(marker, map);
var markerBox = ref.markerBox;
var positionBox = ref.positionBox;
var isVisible = ref.isVisible;
if (markerBox && isVisible) {
markerBoxes.push(markerBox);
}
if (positionBox) {
positionBoxes.push(positionBox);
}
});
this._markersTree.load(markerBoxes);
this._positionsTree.load(positionBoxes);
},
removeMarker: function removeMarker(marker) {
var latLng = marker.getLatLng();
var isVisible = this._map.getBounds().contains(latLng);
var positionBox = {
minX: latLng.lng,
minY: latLng.lat,
maxX: latLng.lng,
maxY: latLng.lat,
marker: marker,
};
this._positionsTree.remove(positionBox, function (a, b) {
return a.marker._leaflet_id === b.marker._leaflet_id;
});
if (isVisible) {
this._redraw(true);
}
},
// remove multiple markers (better for rBush performance)
removeMarkers: function removeMarkers(markers) {
var this$1 = this;
var hasChanged = false;
markers.forEach(function (marker) {
var latLng = marker.getLatLng();
var isVisible = this$1._map.getBounds().contains(latLng);
var positionBox = {
minX: latLng.lng,
minY: latLng.lat,
maxX: latLng.lng,
maxY: latLng.lat,
marker: marker,
};
this$1._positionsTree.remove(positionBox, function (a, b) {
return a.marker._leaflet_id === b.marker._leaflet_id;
});
if (isVisible) {
hasChanged = true;
}
});
if (hasChanged) {
this._redraw(true);
}
},
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//
// leaflet: default methods
//
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
initialize: function initialize(options) {
L.Util.setOptions(this, options);
},
// called by Leaflet on `map.addLayer`
onAdd: function onAdd(map) {
this._map = map;
if (!this._canvas) this._initCanvas();
this.getPane().appendChild(this._canvas);
map.on("moveend", this._reset, this);
map.on("resize", this._reset, this);
map.on("click", this._fire, this);
map.on("mousemove", this._fire, this);
if (map._zoomAnimated) {
map.on("zoomanim", this._animateZoom, this);
}
this._reset();
},
// called by Leaflet
onRemove: function onRemove(map) {
this.getPane().removeChild(this._canvas);
map.off("click", this._fire, this);
map.off("mousemove", this._fire, this);
map.off("moveend", this._reset, this);
map.off("resize", this._reset, this);
if (map._zoomAnimated) {
map.off("zoomanim", this._animateZoom, this);
}
},
setOptions: function setOptions(options) {
L.Util.setOptions(this, options);
return this.redraw();
},
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//
// private: global methods
//
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
_initCanvas: function _initCanvas() {
var ref = this._map.getSize();
var x = ref.x;
var y = ref.y;
var isAnimated = this._map.options.zoomAnimation && L.Browser.any3d;
this._canvas = L.DomUtil.create(
"canvas",
"leaflet-markers-canvas-layer leaflet-layer"
);
this._canvas.width = x;
this._canvas.height = y;
this._context = this._canvas.getContext("2d");
L.DomUtil.addClass(
this._canvas,
("leaflet-zoom-" + (isAnimated ? "animated" : "hide"))
);
},
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//
// private: marker methods
//
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
_addMarker: function _addMarker(marker, map) {
if (marker.options.pane !== "markerPane" || !marker.options.icon) {
console.error("This is not a marker", marker);
return { markerBox: null, positionBox: null, isVisible: null };
}
// required for pop-up and tooltip
marker._map = map;
// add _leaflet_id property
L.Util.stamp(marker);
var latLng = marker.getLatLng();
var isVisible = map.getBounds().contains(latLng);
var ref = map.latLngToContainerPoint(latLng);
var x = ref.x;
var y = ref.y;
var ref$1 = marker.options.icon.options;
var iconSize = ref$1.iconSize;
var iconAnchor = ref$1.iconAnchor;
var markerBox = {
minX: x - iconAnchor[0],
minY: y - iconAnchor[1],
maxX: x + iconSize[0] - iconAnchor[0],
maxY: y + iconSize[1] - iconAnchor[1],
marker: marker,
};
var positionBox = {
minX: latLng.lng,
minY: latLng.lat,
maxX: latLng.lng,
maxY: latLng.lat,
marker: marker,
};
if (isVisible) {
this._drawMarker(marker, { x: x, y: y });
}
this._markers.push(marker);
return { markerBox: markerBox, positionBox: positionBox, isVisible: isVisible };
},
_drawMarker: function _drawMarker(marker, ref) {
if (!this._map) return;
var this$1 = this;
var x = ref.x;
var y = ref.y;
var ref$1 = marker.options.icon.options;
var iconUrl = ref$1.iconUrl;
if (marker.image) {
this._drawImage(marker, { x: x, y: y });
} else if (this._icons[iconUrl]) {
marker.image = this._icons[iconUrl].image;
if (this._icons[iconUrl].isLoaded) {
this._drawImage(marker, { x: x, y: y });
} else {
this._icons[iconUrl].elements.push({ marker: marker, x: x, y: y });
}
} else {
var image = new Image();
image.src = iconUrl;
marker.image = image;
this._icons[iconUrl] = {
image: image,
isLoaded: false,
elements: [{ marker: marker, x: x, y: y }],
};
image.onload = function () {
this$1._icons[iconUrl].isLoaded = true;
this$1._icons[iconUrl].elements.forEach(function (ref) {
var marker = ref.marker;
var x = ref.x;
var y = ref.y;
this$1._drawImage(marker, { x: x, y: y });
});
};
}
},
_drawImage: function _drawImage(marker, ref) {
var x = ref.x;
var y = ref.y;
var ref$1 = marker.options.icon.options;
var rotationAngle = ref$1.rotationAngle;
var iconAnchor = ref$1.iconAnchor;
var iconSize = ref$1.iconSize;
var angle = rotationAngle || 0;
this._context.save();
this._context.translate(x, y);
this._context.rotate((angle * Math.PI) / 180);
this._context.drawImage(
marker.image,
-iconAnchor[0],
-iconAnchor[1],
iconSize[0],
iconSize[1]
);
this._context.restore();
},
_redraw: function _redraw(clear) {
var this$1 = this;
if (clear) {
this._context.clearRect(0, 0, this._canvas.width, this._canvas.height);
}
if (!this._map || !this._positionsTree) { return; }
var mapBounds = this._map.getBounds();
var mapBoundsBox = {
minX: mapBounds.getWest(),
minY: mapBounds.getSouth(),
maxX: mapBounds.getEast(),
maxY: mapBounds.getNorth(),
};
// draw only visible markers
var markers = [];
this._positionsTree.search(mapBoundsBox).forEach(function (ref) {
var marker = ref.marker;
var latLng = marker.getLatLng();
var ref$1 = this$1._map.latLngToContainerPoint(latLng);
var x = ref$1.x;
var y = ref$1.y;
var ref$2 = marker.options.icon.options;
var iconSize = ref$2.iconSize;
var iconAnchor = ref$2.iconAnchor;
var markerBox = {
minX: x - iconAnchor[0],
minY: y - iconAnchor[1],
maxX: x + iconSize[0] - iconAnchor[0],
maxY: y + iconSize[1] - iconAnchor[1],
marker: marker,
};
markers.push(markerBox);
this$1._drawMarker(marker, { x: x, y: y });
});
this._markersTree.clear();
this._markersTree.load(markers);
},
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//
// private: event methods
//
// * * * * * * * * * * * * * * * * * * * * * * * * * * * *
_reset: function _reset() {
var topLeft = this._map.containerPointToLayerPoint([0, 0]);
L.DomUtil.setPosition(this._canvas, topLeft);
var ref = this._map.getSize();
var x = ref.x;
var y = ref.y;
this._canvas.width = x;
this._canvas.height = y;
this._redraw();
},
_fire: function _fire(event) {
if (!this._markersTree) { return; }
var ref = event.containerPoint;
var x = ref.x;
var y = ref.y;
var markers = this._markersTree.search({
minX: x,
minY: y,
maxX: x,
maxY: y,
});
if (markers && markers.length) {
this._map._container.style.cursor = "pointer";
var marker = markers[0].marker;
if (event.type === "click") {
if (marker.listens("click")) {
marker.fire("click");
}
}
if (event.type === "mousemove") {
if (this._mouseOverMarker && this._mouseOverMarker !== marker) {
if (this._mouseOverMarker.listens("mouseout")) {
this._mouseOverMarker.fire("mouseout");
}
}
if (!this._mouseOverMarker || this._mouseOverMarker !== marker) {
this._mouseOverMarker = marker;
if (marker.listens("mouseover")) {
marker.fire("mouseover");
}
}
}
} else {
this._map._container.style.cursor = "";
if (event.type === "mousemove" && this._mouseOverMarker) {
if (this._mouseOverMarker.listens("mouseout")) {
this._mouseOverMarker.fire("mouseout");
}
delete this._mouseOverMarker;
}
}
},
_animateZoom: function _animateZoom(event) {
var scale = this._map.getZoomScale(event.zoom);
var offset = this._map._latLngBoundsToNewLayerBounds(
this._map.getBounds(),
event.zoom,
event.center
).min;
L.DomUtil.setTransform(this._canvas, offset, scale);
},
};
L.MarkersCanvas = L.Layer.extend(markersCanvas);
})));

Wyświetl plik

@ -1,6 +1,6 @@
{
"name": "WebODM",
"version": "2.0.0",
"version": "2.0.1",
"description": "User-friendly, extendable application and API for processing aerial imagery.",
"main": "index.js",
"scripts": {
@ -51,6 +51,7 @@
"proj4": "^2.4.3",
"qrcode.react": "^0.7.2",
"raw-loader": "^0.5.1",
"rbush": "^3.0.1",
"react": "^16.4.0",
"react-dom": "^16.4.0",
"react-router": "^4.1.1",