- npm updates

- draw bounding box geometry
- enter coverage information (elevation and depth)
This commit is contained in:
Kaimbacher 2023-05-02 18:10:32 +02:00
parent 4abcfe7135
commit e110826e1a
12 changed files with 929 additions and 576 deletions

View file

@ -8,7 +8,7 @@
ref="inputDraw"
class="inline-flex cursor-pointer justify-center items-center whitespace-nowrap focus:outline-none transition-colors duration-150 border rounded ring-blue-700 text-black border-teal-50 hover:bg-gray-200 text-sm p-1"
type="button"
:class="[isToggled ? 'cursor-not-allowed bg-gray-200' : 'bg-teal-50 is-active']"
:class="[_enabled ? 'cursor-not-allowed bg-gray-200' : 'bg-teal-50 is-active']"
@click.prevent="draw"
>
<BaseIcon v-if="mdiDrawPen" :path="mdiDrawPen" />
@ -22,10 +22,12 @@ import { Component, Vue, Prop } from 'vue-facing-decorator';
import BaseIcon from '@/Components/BaseIcon.vue';
import { mdiDrawPen } from '@mdi/js';
import { MapService } from '@/Stores/map.service';
// import { Map } from 'leaflet';
// import { LatLngBoundsExpression, toLatLngBounds } from 'leaflet/src/geo/LatLngBounds';
import { Map } from 'leaflet/src/map/index';
// import { LayerGroup } from 'leaflet/src/layer/LayerGroup';
import { Marker } from 'leaflet';
// import { LatLngBounds, Rectangle } from 'leaflet';
import * as DomEvent from 'leaflet/src/dom/DomEvent';
import { Rectangle } from 'leaflet/src/layer/vector/Rectangle';
import { LatLngBounds } from 'leaflet/src/geo/LatLngBounds';
@Component({
name: 'draw-control',
@ -34,16 +36,34 @@ import { Marker } from 'leaflet';
},
})
export default class DrawControlComponent extends Vue {
TYPE = 'rectangle';
/**
* class properties.
*/
mdiDrawPen = mdiDrawPen;
featuresLayer;
// options = {
// zIndex: 1000,
// // markerClass: Marker, // CylinderGeometry,
// drawingCSSClass: 'gba-editable-drawing',
// drawingCursor: 'crosshair',
// };
options = {
zIndex: 1000,
markerClass: Marker, // CylinderGeometry,
drawingCSSClass: 'gba-editable-drawing',
drawingCursor: 'crosshair',
shapeOptions: {
stroke: true,
color: '#22C55E',
weight: 4,
opacity: 0.5,
fill: true,
fillColor: '#22C55E', //same as color by default
fillOpacity: 0.2,
clickable: true,
},
repeatMode: true,
showArea: true, //Whether to show the area in the tooltip
metric: true, // Whether to use the metric measurement system or imperial
};
/**
@ -54,43 +74,189 @@ export default class DrawControlComponent extends Vue {
@Prop public southWest;
@Prop public northEast;
public isToggled = false;
mapService = MapService();
// try:
public _enabled;
private _map: Map;
private _isDrawing: boolean = false;
private _startLatLng;
private _mapDraggable;
private _shape: Rectangle | undefined;
// @method enable(): this
// Enables the handler
enable() {
if (this._enabled) {
return this;
}
this._enabled = true;
this.addHooks();
return this;
}
// @method disable(): this
// Disables the handler
disable() {
if (!this._enabled) {
return this;
}
this._enabled = false;
this.removeHooks();
return this;
}
// @method enabled(): Boolean
// Returns `true` if the handler is enabled
enabled() {
return !!this._enabled;
}
// @Ref('inputDraw') private _inputDraw: HTMLElement;
// SimpleShape
// @method addHooks(): void
// Add listener hooks to this handler.
private addHooks() {
// L.Draw.Feature.prototype.addHooks.call(this);
this._map = this.mapService.getMap(this.mapId);
if (this._map) {
this._mapDraggable = this._map.dragging.enabled();
if (this._mapDraggable) {
this._map.dragging.disable();
}
//TODO refactor: move cursor to styles
// this._container.style.cursor = 'crosshair';
// this._tooltip.updateContent({text: this._initialLabelText});
this._map
.on('mousedown', this._onMouseDown, this)
.on('mousemove', this._onMouseMove, this)
.on('touchstart', this._onMouseDown, this)
.on('touchmove', this._onMouseMove, this);
// we should prevent default, otherwise default behavior (scrolling) will fire,
// and that will cause document.touchend to fire and will stop the drawing
// (circle, rectangle) in touch mode.
// (update): we have to send passive now to prevent scroll, because by default it is {passive: true} now, which means,
// handler can't event.preventDefault
// check the news https://developers.google.com/web/updates/2016/06/passive-event-listeners
document.addEventListener('touchstart', DomEvent.preventDefault, { passive: false });
}
}
// SimpleShape
// @method removeHooks(): void
// Remove listener hooks from this handler.
removeHooks() {
// L.Draw.Feature.prototype.removeHooks.call(this);
if (this._map) {
if (this._mapDraggable) {
this._map.dragging.enable();
}
//TODO refactor: move cursor to styles
// this._container.style.cursor = '';
this._map
.off('mousedown', this._onMouseDown, this)
.off('mousemove', this._onMouseMove, this)
.off('touchstart', this._onMouseDown, this)
.off('touchmove', this._onMouseMove, this);
DomEvent.off(document, 'mouseup', this._onMouseUp, this);
DomEvent.off(document, 'touchend', this._onMouseUp, this);
document.removeEventListener('touchstart', DomEvent.preventDefault);
// If the box element doesn't exist they must not have moved the mouse, so don't need to destroy/return
// if (this._shape) {
// this._map.removeLayer(this._shape);
// // delete this._shape;
// this._shape = undefined;
// }
}
this._isDrawing = false;
}
private _onMouseDown(e) {
this._isDrawing = true;
this._startLatLng = e.latlng;
DomEvent.on(document, 'mouseup', this._onMouseUp, this)
.on(document, 'touchend', this._onMouseUp, this)
.preventDefault(e.originalEvent);
}
private _onMouseMove(e) {
var latlng = e.latlng;
// this._tooltip.updatePosition(latlng);
if (this._isDrawing) {
// this._tooltip.updateContent(this._getTooltipText());
this._drawShape(latlng);
}
}
private _onMouseUp() {
if (this._shape) {
this._fireCreatedEvent(this._shape);
}
// this.removeHooks();
this.disable();
if (this.options.repeatMode) {
this.enable();
}
}
private _fireCreatedEvent(shape) {
var rectangle = new Rectangle(shape.getBounds(), this.options.shapeOptions);
// L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this, rectangle);
this._map.fire('Daw.Event.CREATED', { layer: rectangle, type: this.TYPE });
}
// from Draw Rectangle
_drawShape(latlng) {
if (!this._shape) {
const bounds = new LatLngBounds(this._startLatLng, latlng);
this._shape = new Rectangle(bounds, this.options.shapeOptions);
// this._map.addLayer(this._shape);
this._shape.addTo(this._map);
} else {
this._shape.setBounds(new LatLngBounds(this._startLatLng, latlng));
}
}
public draw() {
// let map: Map = this.mapService.getMap(this.mapId);
// const bounds: LatLngBoundsExpression = toLatLngBounds(this.southWest, this.northEast);
// map.fitBounds(bounds);
if (this.isToggled == true) {
if (this._enabled == true) {
this.disable();
} else {
this.enable();
}
this.isToggled = !this.isToggled;
// this.isToggled = !this.isToggled;
}
private enable() {
//if (this.map.mapTool) this.map.mapTool.on('editable:drawing:start', this.disable.bind(this));
// dom.addClass(this.map.container, 'measure-enabled');
//this.fireAndForward('showmeasure');
this._startMarker(this.southWest, this.options);
}
// private enable() {
// //if (this.map.mapTool) this.map.mapTool.on('editable:drawing:start', this.disable.bind(this));
// // dom.addClass(this.map.container, 'measure-enabled');
// //this.fireAndForward('showmeasure');
// this._startMarker(this.southWest, this.options);
// }
private disable() {
//if (this.map.mapTool) this.map.mapTool.off('editable:drawing:start', this.disable.bind(this));
// dom.removeClass(this.map.container, 'measure-enabled');
// this.featuresLayer.clearLayers();
// //this.fireAndForward('hidemeasure');
// if (this._drawingEditor) {
// this._drawingEditor.cancelDrawing();
// }
}
// private disable() {
// //if (this.map.mapTool) this.map.mapTool.off('editable:drawing:start', this.disable.bind(this));
// // dom.removeClass(this.map.container, 'measure-enabled');
// // this.featuresLayer.clearLayers();
// // //this.fireAndForward('hidemeasure');
// // if (this._drawingEditor) {
// // this._drawingEditor.cancelDrawing();
// // }
// }
// created(): void {
// this.featuresLayer = this._createFeaturesLayer();
@ -103,22 +269,22 @@ export default class DrawControlComponent extends Vue {
// return layerGroup;
// }
private _startMarker(latlng, options) {
let map = this.mapService.getMap(this.mapId);
latlng = map.getCenter().clone();
let markerLayer: Marker = this._createMarker(latlng, options); //.addTo(this.map);
// map.addLayer(markerLayer);
//this.map.addLayer(marker);
//marker.enableEdit(this.map).startDrawing(); //editor.startDrawing() -> registerForDrawing
// let baseEditor = markerLayer.en.enableEdit(this.map);
// baseEditor.startDrawing();
return markerLayer;
}
// private _startMarker(latlng, options) {
// let map = this.mapService.getMap(this.mapId);
// latlng = map.getCenter().clone();
// let markerLayer: Marker = this._createMarker(latlng, options); //.addTo(this.map);
// // map.addLayer(markerLayer);
// //this.map.addLayer(marker);
// //marker.enableEdit(this.map).startDrawing(); //editor.startDrawing() -> registerForDrawing
// // let baseEditor = markerLayer.en.enableEdit(this.map);
// // baseEditor.startDrawing();
// return markerLayer;
// }
private _createMarker(latlng, options): Marker {
// return this._createLayer((options && options.markerClass) || this.options.markerClass, latlng, options);
return new Marker(latlng, options);
}
// private _createMarker(latlng, options): Marker {
// // return this._createLayer((options && options.markerClass) || this.options.markerClass, latlng, options);
// return new Marker(latlng, options);
// }
// private _createLayer(klass, latlngs, options) {
// options = util.extend({ editOptions: { mapTool: this } }, options);
@ -140,7 +306,7 @@ export default class DrawControlComponent extends Vue {
position: absolute;
left: 10px;
top: 100px;
z-index: 500;
z-index: 40;
}
.btn-group-vertical button {

View file

@ -2,7 +2,7 @@
<div style="position: relative">
<!-- <Map className="h-36" :center="state.center" :zoom="state.zoom"> // map component content </Map> -->
<div :id="mapId" class="map-container mapDesktop rounded">
<ZoomControlComponent :mapId="mapId"></ZoomControlComponent>
<ZoomControlComponent ref="zoom" :mapId="mapId"></ZoomControlComponent>
<DrawControlComponent :mapId="mapId" :southWest="southWest" :northEast="northEast"></DrawControlComponent>
</div>
</div>
@ -10,7 +10,7 @@
<script lang="ts">
import { EventEmitter } from './EventEmitter';
import { Component, Vue, Prop } from 'vue-facing-decorator';
import { Component, Vue, Prop, Ref } from 'vue-facing-decorator';
// import type { Coverage } from '@/Dataset';
// import { Map, Control, MapOptions, LatLngBoundsExpression, tileLayer, latLng, latLngBounds, FeatureGroup } from 'leaflet';
import { Map } from 'leaflet/src/map/index';
@ -27,6 +27,54 @@ import { LayerOptions, LayerMap } from './LayerOptions';
import { MapService } from '@/Stores/map.service';
import ZoomControlComponent from './zoom.component.vue';
import DrawControlComponent from './draw.component.vue';
import { Coverage } from '@/Dataset';
import {canvas} from 'leaflet/src/layer/vector/Canvas';
import {svg} from 'leaflet/src/layer/vector/SVG';
Map.include({
// @namespace Map; @method getRenderer(layer: Path): Renderer
// Returns the instance of `Renderer` that should be used to render the given
// `Path`. It will ensure that the `renderer` options of the map and paths
// are respected, and that the renderers do exist on the map.
getRenderer: function (layer) {
// @namespace Path; @option renderer: Renderer
// Use this specific instance of `Renderer` for this path. Takes
// precedence over the map's [default renderer](#map-renderer).
var renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;
if (!renderer) {
renderer = this._renderer = this._createRenderer();
}
if (!this.hasLayer(renderer)) {
this.addLayer(renderer);
}
return renderer;
},
_getPaneRenderer: function (name) {
if (name === 'overlayPane' || name === undefined) {
return false;
}
var renderer = this._paneRenderers[name];
if (renderer === undefined) {
renderer = this._createRenderer({pane: name});
this._paneRenderers[name] = renderer;
}
return renderer;
},
_createRenderer: function (options) {
// @namespace Map; @option preferCanvas: Boolean = false
// Whether `Path`s should be rendered on a `Canvas` renderer.
// By default, all `Path`s are rendered in a `SVG` renderer.
return (this.options.preferCanvas && canvas(options)) || svg(options);
}
});
const DEFAULT_BASE_LAYER_NAME = 'BaseLayer';
// const DEFAULT_BASE_LAYER_URL = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
@ -36,7 +84,7 @@ const DEFAULT_BASE_LAYER_ATTRIBUTION = '&copy; <a target="_blank" href="http://o
name: 'MapComponent',
components: {
ZoomControlComponent,
DrawControlComponent
DrawControlComponent,
},
})
export default class MapComponent extends Vue {
@ -53,6 +101,9 @@ export default class MapComponent extends Vue {
@Prop()
public mapOptions: MapOptions;
@Prop()
public coverage: Coverage;
// markerService: MarkerService
/**
* Bounds for the map
@ -69,12 +120,13 @@ export default class MapComponent extends Vue {
@Prop()
public baseMaps: LayerMap;
@Ref('zoom') private zoom: ZoomControlComponent;
mapService = MapService();
southWest;
northEast;
/**
* Informs when initialization is done with map id.
*/
@ -88,6 +140,11 @@ export default class MapComponent extends Vue {
mounted(): void {
this.initMap();
this.map.on('zoomend zoomlevelschange', this.zoom.updateDisabled, this.zoom);
}
unmounted() {
this.map.off('zoomend zoomlevelschange');
}
public deleteTest(): void {
@ -116,6 +173,28 @@ export default class MapComponent extends Vue {
const attributionControl = new Attribution().addTo(this.map);
attributionControl.setPrefix(false);
map.on(
'Daw.Event.CREATED',
function (event) {
// drawnItems.clearLayers();
// var type = event.type;
var layer = event.layer;
// if (type === "rectancle") {
// layer.bindPopup("A popup!" + layer.getBounds().toBBoxString());
var bounds = layer.getBounds();
this.coverage.x_min = bounds.getSouthWest().lng;
this.coverage.y_min = bounds.getSouthWest().lat;
// console.log(this.geolocation.xmin);
this.coverage.x_max = bounds.getNorthEast().lng;
this.coverage.y_max = bounds.getNorthEast().lat;
// }
// drawnItems.addLayer(layer);
},
this,
);
// Initialise the FeatureGroup to store editable layers
// let drawnItems = (this.drawnItems = new FeatureGroup());
// map.addLayer(drawnItems);
@ -150,4 +229,7 @@ export default class MapComponent extends Vue {
height: 600px; /* <-- map height */
width: 100%;
}
.leaflet-pane {
z-index: 30;
}
</style>

View file

@ -2,7 +2,7 @@
<div class="gba-control-zoom btn-group-vertical">
<button
ref="inputPlus"
class="inline-flex cursor-pointer justify-center items-center whitespace-nowrap focus:outline-none transition-colors duration-150 border rounded ring-blue-700 bg-teal-50 text-black border-teal-50 hover:bg-gray-200 text-sm p-1"
class="disabled:bg-gray-200 inline-flex cursor-pointer justify-center items-center whitespace-nowrap focus:outline-none transition-colors duration-150 border rounded ring-blue-700 bg-teal-50 text-black border-teal-50 text-sm p-1"
type="button"
@click.prevent="zoomIn"
>
@ -11,7 +11,7 @@
<button
ref="inputMinus"
class="inline-flex cursor-pointer justify-center items-center whitespace-nowrap focus:outline-none transition-colors duration-150 border rounded ring-blue-700 bg-teal-50 text-black border-teal-50 hover:bg-gray-200 text-sm p-1"
class="disabled:bg-gray-200 inline-flex cursor-pointer justify-center items-center whitespace-nowrap focus:outline-none transition-colors duration-150 border rounded ring-blue-700 bg-teal-50 text-black border-teal-50 text-sm p-1"
type="button"
@click.prevent="zoomOut"
>
@ -42,8 +42,8 @@ export default class ZoomControlComponent extends Vue {
*/
@Prop() public mapId: string;
@Ref('inputPlus') private _inputPlus: HTMLElement;
@Ref('inputMinus') private _inpuMinus: HTMLElement;
@Ref('inputPlus') inputPlus: HTMLButtonElement;
@Ref('inputMinus') inputMinus: HTMLButtonElement;
mapService = MapService();
map;
@ -71,19 +71,19 @@ export default class ZoomControlComponent extends Vue {
let map = this.mapService.getMap(this.mapId);
// let className = 'leaflet-disabled';
// this._inputPlus.nativeElement.disabled = false;
this._inputPlus.setAttribute('aria-disabled', 'false');
this.inputPlus.disabled = false;
this.inputPlus.setAttribute('aria-disabled', 'false');
// this._inpuMinus.nativeElement.disabled = false;
this._inpuMinus.setAttribute('aria-disabled', 'false');
this.inputMinus.disabled = false;
this.inputMinus.setAttribute('aria-disabled', 'false');
if (map.getZoom() === map.getMinZoom()) {
// this._inpuMinus.nativeElement.disabled = true;
this._inpuMinus.setAttribute('aria-disabled', 'true');
this.inputMinus.disabled = true;
this.inputMinus.setAttribute('aria-disabled', 'true');
}
if (map.getZoom() === map.getMaxZoom()) {
// this._inputPlus.nativeElement.disabled = true;
this._inputPlus.setAttribute('aria-disabled', 'true');
this.inputPlus.disabled = true;
this.inputPlus.setAttribute('aria-disabled', 'true');
}
}
}
@ -100,7 +100,7 @@ export default class ZoomControlComponent extends Vue {
position: absolute;
left: 10px;
top: 10px;
z-index: 500;
z-index: 40;
}
.btn-group-vertical button {

View file

@ -83,7 +83,7 @@ const logout = async() => {
<template>
<nav
class="top-0 left-0 right-0 fixed bg-gray-50 h-14 z-30 w-screen transition-position xl:pl-60 lg:w-auto dark:bg-slate-800"
class="top-0 left-0 right-0 fixed bg-gray-50 h-14 z-50 w-screen transition-position xl:pl-60 lg:w-auto dark:bg-slate-800"
>
<div class="flex lg:items-stretch" :class="containerMaxW">
<div class="flex-1 items-stretch flex h-14">