2023-04-06 16:56:41 +00:00
|
|
|
<template>
|
2023-04-12 07:26:45 +00:00
|
|
|
<div ref="drawControl" class="gba-control-draw btn-group-vertical map-control">
|
2023-04-06 16:56:41 +00:00
|
|
|
<!-- <button type="button" class="button is-light is-small" (click)="locateUser()" [ngClass]="isToggled ? 'is-primary': 'is-active'">
|
|
|
|
<fa-icon [icon]="faSearchLocation"></fa-icon>
|
|
|
|
</button> -->
|
2023-04-12 07:26:45 +00:00
|
|
|
<!-- -->
|
2024-07-08 11:52:20 +00:00
|
|
|
<button ref="inputDraw"
|
2023-04-06 16:56:41 +00:00
|
|
|
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"
|
2024-07-08 11:52:20 +00:00
|
|
|
type="button" :class="[_enabled ? 'cursor-not-allowed bg-cyan-200' : 'bg-teal-50 is-active']"
|
|
|
|
@click.prevent="toggleDraw">
|
2023-04-06 16:56:41 +00:00
|
|
|
<BaseIcon v-if="mdiDrawPen" :path="mdiDrawPen" />
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
import { Component, Vue, Prop } from 'vue-facing-decorator';
|
|
|
|
|
|
|
|
import BaseIcon from '@/Components/BaseIcon.vue';
|
|
|
|
import { mdiDrawPen } from '@mdi/js';
|
2023-04-12 07:26:45 +00:00
|
|
|
import { MapService } from '@/Stores/map.service';
|
2023-05-02 16:10:32 +00:00
|
|
|
import { Map } from 'leaflet/src/map/index';
|
2023-04-12 07:26:45 +00:00
|
|
|
// import { LayerGroup } from 'leaflet/src/layer/LayerGroup';
|
2023-05-02 16:10:32 +00:00
|
|
|
// import { LatLngBounds, Rectangle } from 'leaflet';
|
2023-06-01 12:29:56 +00:00
|
|
|
import { on, off, preventDefault } from 'leaflet/src/dom/DomEvent';
|
2023-05-02 16:10:32 +00:00
|
|
|
import { Rectangle } from 'leaflet/src/layer/vector/Rectangle';
|
|
|
|
import { LatLngBounds } from 'leaflet/src/geo/LatLngBounds';
|
2024-07-08 11:52:20 +00:00
|
|
|
import { LatLng } from 'leaflet';
|
|
|
|
import { LeafletMouseEvent } from 'leaflet';
|
2023-04-06 16:56:41 +00:00
|
|
|
|
|
|
|
@Component({
|
2023-04-12 07:26:45 +00:00
|
|
|
name: 'draw-control',
|
2023-04-06 16:56:41 +00:00
|
|
|
components: {
|
|
|
|
BaseIcon,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
export default class DrawControlComponent extends Vue {
|
2023-10-23 13:27:39 +00:00
|
|
|
public TYPE = 'rectangle';
|
2023-04-06 16:56:41 +00:00
|
|
|
mdiDrawPen = mdiDrawPen;
|
2023-10-23 13:27:39 +00:00
|
|
|
// private featuresLayer;
|
2023-05-02 16:10:32 +00:00
|
|
|
|
2023-04-12 07:26:45 +00:00
|
|
|
options = {
|
2023-05-02 16:10:32 +00:00
|
|
|
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
|
2023-04-12 07:26:45 +00:00
|
|
|
};
|
2023-04-06 16:56:41 +00:00
|
|
|
|
|
|
|
@Prop() public mapId: string;
|
2023-04-12 07:26:45 +00:00
|
|
|
// @Prop() public map: Map;
|
2024-07-08 11:52:20 +00:00
|
|
|
@Prop public southWest: LatLng;
|
|
|
|
@Prop public northEast: LatLng;
|
2023-10-23 13:27:39 +00:00
|
|
|
@Prop({
|
2023-10-31 14:38:43 +00:00
|
|
|
default: true,
|
|
|
|
})
|
|
|
|
public preserve: boolean;
|
2023-05-09 12:43:16 +00:00
|
|
|
|
2023-04-12 07:26:45 +00:00
|
|
|
mapService = MapService();
|
2024-07-08 11:52:20 +00:00
|
|
|
public _enabled: boolean;
|
2023-05-02 16:10:32 +00:00
|
|
|
private _map: Map;
|
|
|
|
private _isDrawing: boolean = false;
|
2024-07-08 11:52:20 +00:00
|
|
|
private _startLatLng: LatLng;
|
|
|
|
private _mapDraggable: boolean;
|
2023-05-02 16:10:32 +00:00
|
|
|
private _shape: Rectangle | undefined;
|
|
|
|
|
|
|
|
enable() {
|
|
|
|
if (this._enabled) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._enabled = true;
|
|
|
|
this.addHooks();
|
2024-07-08 11:52:20 +00:00
|
|
|
this._map.control = this;
|
2023-05-02 16:10:32 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
disable() {
|
|
|
|
if (!this._enabled) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._enabled = false;
|
|
|
|
this.removeHooks();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
enabled() {
|
|
|
|
return !!this._enabled;
|
|
|
|
}
|
2023-04-06 16:56:41 +00:00
|
|
|
|
|
|
|
// @Ref('inputDraw') private _inputDraw: HTMLElement;
|
|
|
|
|
2023-05-02 16:10:32 +00:00
|
|
|
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
|
2023-05-09 12:43:16 +00:00
|
|
|
// this._map.domElement.style.cursor = 'crosshair';
|
2023-06-01 12:29:56 +00:00
|
|
|
this._map._container.style.cursor = 'crosshair';
|
2023-05-02 16:10:32 +00:00
|
|
|
// this._tooltip.updateContent({text: this._initialLabelText});
|
2024-07-08 11:52:20 +00:00
|
|
|
|
2023-05-02 16:10:32 +00:00
|
|
|
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
|
2023-05-09 12:43:16 +00:00
|
|
|
// document.addEventListener('touchstart', preventDefault, { passive: false });
|
2023-05-02 16:10:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-23 13:27:39 +00:00
|
|
|
private removeHooks() {
|
2023-05-02 16:10:32 +00:00
|
|
|
// L.Draw.Feature.prototype.removeHooks.call(this);
|
|
|
|
if (this._map) {
|
|
|
|
if (this._mapDraggable) {
|
|
|
|
this._map.dragging.enable();
|
|
|
|
}
|
|
|
|
|
|
|
|
//TODO refactor: move cursor to styles
|
2023-05-09 12:43:16 +00:00
|
|
|
this._map._container.style.cursor = '';
|
2023-05-02 16:10:32 +00:00
|
|
|
|
|
|
|
this._map
|
|
|
|
.off('mousedown', this._onMouseDown, this)
|
|
|
|
.off('mousemove', this._onMouseMove, this)
|
|
|
|
.off('touchstart', this._onMouseDown, this)
|
|
|
|
.off('touchmove', this._onMouseMove, this);
|
|
|
|
|
2023-05-03 08:02:48 +00:00
|
|
|
off(document, 'mouseup', this._onMouseUp, this);
|
|
|
|
off(document, 'touchend', this._onMouseUp, this);
|
2023-05-02 16:10:32 +00:00
|
|
|
|
2023-05-09 12:43:16 +00:00
|
|
|
// document.removeEventListener('touchstart', preventDefault);
|
2023-05-02 16:10:32 +00:00
|
|
|
|
|
|
|
// If the box element doesn't exist they must not have moved the mouse, so don't need to destroy/return
|
2023-10-23 13:27:39 +00:00
|
|
|
if (this._shape && this.preserve == false) {
|
|
|
|
this._map.removeLayer(this._shape);
|
|
|
|
// delete this._shape;
|
|
|
|
this._shape = undefined;
|
|
|
|
}
|
2023-05-02 16:10:32 +00:00
|
|
|
}
|
|
|
|
this._isDrawing = false;
|
|
|
|
}
|
|
|
|
|
2024-07-08 11:52:20 +00:00
|
|
|
private _onMouseDown(e: LeafletMouseEvent) {
|
2023-05-02 16:10:32 +00:00
|
|
|
this._isDrawing = true;
|
|
|
|
this._startLatLng = e.latlng;
|
|
|
|
|
2023-05-03 08:02:48 +00:00
|
|
|
// DomEvent.on(document, 'mouseup', this._onMouseUp, this)
|
|
|
|
// .on(document, 'touchend', this._onMouseUp, this)
|
|
|
|
// .preventDefault(e.originalEvent);
|
|
|
|
on(document, 'mouseup', this._onMouseUp, this);
|
|
|
|
on(document, 'touchend', this._onMouseUp, this);
|
|
|
|
preventDefault(e.originalEvent);
|
2023-05-02 16:10:32 +00:00
|
|
|
}
|
|
|
|
|
2024-07-08 11:52:20 +00:00
|
|
|
private _onMouseMove(e: LeafletMouseEvent) {
|
2023-05-02 16:10:32 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-08 11:52:20 +00:00
|
|
|
private _fireCreatedEvent(shape: Rectangle) {
|
2023-05-02 16:10:32 +00:00
|
|
|
var rectangle = new Rectangle(shape.getBounds(), this.options.shapeOptions);
|
|
|
|
// L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this, rectangle);
|
2023-10-23 13:27:39 +00:00
|
|
|
this._map.fire('Draw.Event.CREATED', { layer: rectangle, type: this.TYPE });
|
2023-05-02 16:10:32 +00:00
|
|
|
}
|
|
|
|
|
2024-07-08 11:52:20 +00:00
|
|
|
public removeShape() {
|
|
|
|
if (this._shape) {
|
|
|
|
this._map.removeLayer(this._shape);
|
|
|
|
// delete this._shape;
|
|
|
|
this._shape = undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public drawShape(southWest: LatLng, northEast: LatLng) {
|
2023-06-01 12:29:56 +00:00
|
|
|
if (!this._shape) {
|
|
|
|
const bounds = new LatLngBounds(southWest, northEast);
|
|
|
|
this._shape = new Rectangle(bounds, this.options.shapeOptions);
|
|
|
|
// this._map.addLayer(this._shape);
|
|
|
|
this._map = this.mapService.getMap(this.mapId);
|
|
|
|
this._shape.addTo(this._map);
|
|
|
|
} else {
|
|
|
|
this._shape.setBounds(new LatLngBounds(southWest, northEast));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-02 16:10:32 +00:00
|
|
|
// from Draw Rectangle
|
2024-07-08 11:52:20 +00:00
|
|
|
private _drawShape(latlng: LatLng) {
|
2023-05-02 16:10:32 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-23 13:27:39 +00:00
|
|
|
public toggleDraw() {
|
2023-05-02 16:10:32 +00:00
|
|
|
if (this._enabled == true) {
|
2023-04-12 07:26:45 +00:00
|
|
|
this.disable();
|
|
|
|
} else {
|
|
|
|
this.enable();
|
|
|
|
}
|
2023-04-06 16:56:41 +00:00
|
|
|
}
|
2023-04-12 07:26:45 +00:00
|
|
|
|
2023-05-02 16:10:32 +00:00
|
|
|
// 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);
|
|
|
|
// }
|
2023-04-12 07:26:45 +00:00
|
|
|
|
2023-05-02 16:10:32 +00:00
|
|
|
// 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();
|
|
|
|
// // }
|
|
|
|
// }
|
2023-04-06 16:56:41 +00:00
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="css">
|
|
|
|
.gba-control-draw {
|
|
|
|
-webkit-user-select: none;
|
|
|
|
-moz-user-select: none;
|
|
|
|
-ms-user-select: none;
|
|
|
|
user-select: none;
|
|
|
|
cursor: pointer;
|
|
|
|
border-radius: 4px;
|
|
|
|
position: absolute;
|
|
|
|
left: 10px;
|
|
|
|
top: 100px;
|
2024-06-14 10:38:04 +00:00
|
|
|
z-index: 999;
|
2023-04-06 16:56:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
.btn-group-vertical button {
|
|
|
|
display: block;
|
|
|
|
|
|
|
|
margin-left: 0;
|
|
|
|
margin-top: 0.5em;
|
|
|
|
}
|
|
|
|
</style>
|