Skip to content

Commit

Permalink
Added bounding box map
Browse files Browse the repository at this point in the history
  • Loading branch information
RoryPTB committed Jan 25, 2024
1 parent 670c7c8 commit a372c2a
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 69 deletions.
82 changes: 25 additions & 57 deletions src/components/BboxEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
<l-tile-layer v-for="tileProvider in tileProviders" :key="tileProvider.name" :name="tileProvider.name"
:visible="tileProvider.visible" :url="tileProvider.url" :attribution="tileProvider.attribution"
layer-type="base" />
<l-feature-group ref="features">
<l-feature-group>
<l-rectangle v-if="rectangle.visible" :autoPan="true" :autofocus="true" :bounds="rectangle.bounds"
:draggable="true"></l-rectangle>
:draggable="false"></l-rectangle>
</l-feature-group>
</l-map>
</v-img>
Expand All @@ -19,11 +19,11 @@
<script>
import { defineComponent, ref, watch } from 'vue';
import { LMap, LTileLayer, LControlLayers, LRectangle, LFeatureGroup } from "@vue-leaflet/vue-leaflet";
import * as L from "leaflet";
import { LatLng, LatLngBounds } from "leaflet";
import "leaflet/dist/leaflet.css";
// Allow the user to draw the bounding box
import 'leaflet-draw';
import 'leaflet-draw/dist/leaflet.draw.css';
// // Allow the user to draw the bounding box
// import 'leaflet-draw';
// import 'leaflet-draw/dist/leaflet.draw.css';
export default defineComponent({
name: "BboxEditor",
Expand All @@ -35,58 +35,27 @@ export default defineComponent({
LFeatureGroup
},
props: {
inputFeature: {},
boxBounds: {},
},
setup(props, { emit }) {
// Reactive variables
const map = ref(null);
const features = ref(null);
const zoom = ref(1.5);
const rectangle = ref({
visible: true,
visible: false,
center: [0, 0],
bounds: [[0, 0], [0, 0]]
});
// Methods
// Add the drawing controls
const loadMapObjects = () => {
if (map.value?.mapObject) {
let drawControl = new L.Control.Draw({
// Only allow the user to draw a rectangle (bounding box
draw: {
polyline: false,
polygon: false,
circle: false,
marker: false,
circlemarker: false,
rectangle: true
}
if (map.mapObject?.on) {
map.mapObject.on("draw:created", (event) => {
console.log(event);
});
map.value.mapObject.addControl(drawControl);
// Save the corresponding bounding box coordinates
map.value.mapObject.on('draw:created', function (e) {
let type = e.layerType,
layer = e.layer;
if (type === 'rectangle') {
let bounds = layer.getBounds();
let northLatitude = bounds.getNorth();
let southLatitude = bounds.getSouth();
let eastLongitude = bounds.getEast();
let westLongitude = bounds.getWest();
// Emit an event with the bounding box coordinates to be accessed by form
emit('update-geometry', { northLatitude, southLatitude, eastLongitude, westLongitude });
// Add the drawn layer to the map
map.value.mapObject.addLayer(layer);
}
});
}
};
emit('loaded');
};
Expand Down Expand Up @@ -119,27 +88,26 @@ export default defineComponent({
const tileProviders = loadBasemaps();
// Watchers
watch(() => props.inputFeature, (input) => {
if (input && input.length === 4) {
const zoom_factor = 0.05;
const topleft = new L.LatLng(input[0], input[1]);
const bottomright = new L.LatLng(input[2], input[3]);
const tmp = new L.LatLngBounds(topleft, bottomright);
rectangle.value.center = tmp.getCenter();
rectangle.value.bounds = [tmp.getNorthWest(), tmp.getSouthEast()];
map.value?.mapObject.fitBounds([
[input[0] + zoom_factor, input[1] + zoom_factor],
[input[2] - zoom_factor, input[3] - zoom_factor]
]);
watch(() => props.boxBounds, () => {
if (props.boxBounds) {
// Use the four input coordinates to create the rectangle
const topLeft = new LatLng(props.boxBounds[0], props.boxBounds[1]);
const bottomRight = new LatLng(props.boxBounds[2], props.boxBounds[3]);
const bounds = new LatLngBounds(topLeft, bottomRight);
// Update the rectangle
rectangle.value.center = bounds.getCenter();
rectangle.value.bounds = [bounds.getNorthWest(), bounds.getSouthEast()];
rectangle.value.visible = true;
} else {
map.value?.mapObject.setZoom(1.5);
// Reset the rectangle
rectangle.value.center = [0, 0];
rectangle.value.bounds = [[0, 0], [0, 0]];
rectangle.value.visible = false;
}
});
return {
map,
features,
zoom,
rectangle,
tileProviders,
Expand Down
140 changes: 140 additions & 0 deletions src/components/BboxEditorOld.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<template>
<v-lazy>
<v-img>
<l-map
ref="map"
:zoom="zoom"
:center="rectangle.center"
@ready="loadMapObjects"
style="height: 300px; width: 100%"
>
<l-control-layers
position="bottomleft"
:collapsed="true"
:sort-layers="true"
/>
<l-tile-layer
v-for="tileProvider in tileProviders"
:key="tileProvider.name"
:name="tileProvider.name"
:visible="tileProvider.visible"
:url="tileProvider.url"
:attribution="tileProvider.attribution"
layer-type="base"
/>
<l-feature-group ref="features">
<l-rectangle
v-if="rectangle.visible"
:autoPan="true"
:autofocus="true"
:bounds="rectangle.bounds"
:draggable="true"
></l-rectangle>
</l-feature-group>
</l-map>
</v-img>
</v-lazy>
</template>

<script>
import { defineComponent, ref, watch } from 'vue';
import { LMap, LTileLayer, LControlLayers, LRectangle, LFeatureGroup } from "@vue-leaflet/vue-leaflet";
import { LatLng, LatLngBounds } from "leaflet";
import "leaflet/dist/leaflet.css";
export default defineComponent({
name: "BboxEditor",
components: {
LMap,
LTileLayer,
LControlLayers,
LRectangle,
LFeatureGroup
},
props: {
inputFeature: {},
},
setup(props, { emit }) {
// Reactive variables
const map = ref(null);
const features = ref(null);
const zoom = ref(1.5);
const rectangle = ref({
visible: false,
center: [0, 0],
bounds: [[0, 0], [0, 0]]
});
// Methods
const loadMapObjects = () => {
map.value.mapObject.on("draw:created", (event) => {
console.log(event);
});
emit('loaded');
};
const loadBasemaps = () => {
return [
{
name: 'OpenStreetMap',
visible: true,
attribution:
'&copy; <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a> contributors',
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
},
{
name: 'OpenTopoMap',
visible: false,
url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
attribution:
'Map data: &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, <a href="http://viewfinderpanoramas.org">SRTM</a> | Map style: &copy; <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)',
},
{
name: 'ESRI World Imagery',
visible: false,
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
attribution: 'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
}
];
};
const tileProviders = loadBasemaps();
// Watchers
watch(() => props.inputFeature, (input) => {
if (input && input.length === 4) {
const zoom_factor = 0.05;
const topleft = new LatLng(input[0], input[1]);
const bottomright = new LatLng(input[2], input[3]);
const tmp = new LatLngBounds(topleft, bottomright);
rectangle.value.center = tmp.getCenter();
rectangle.value.bounds = [tmp.getNorthWest(), tmp.getSouthEast()];
map.value?.mapObject.fitBounds([
[input[0] + zoom_factor, input[1] + zoom_factor],
[input[2] - zoom_factor, input[3] - zoom_factor]
]);
rectangle.value.visible = true;
} else {
map.value?.mapObject.setZoom(1.5);
rectangle.value.center = [0, 0];
rectangle.value.bounds = [[0, 0], [0, 0]];
rectangle.value.visible = false;
}
}, { deep: true });
return {
map,
features,
zoom,
rectangle,
tileProviders,
loadMapObjects
};
}
});
</script>
<style>
@import "leaflet/dist/leaflet.css";
</style>
28 changes: 16 additions & 12 deletions src/components/DiscoveryMetadataForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
<v-row>
<v-col cols="12">
<!-- Bounding box editor -->
<bbox-editor @update-geometry="updateGeometry" :input-feature="bounds"></bbox-editor>
<bbox-editor :box-bounds="bounds"></bbox-editor>
</v-col>
</v-row>
<v-row>
Expand Down Expand Up @@ -495,7 +495,7 @@ export default defineComponent({
// Whether or not the metadata is new or existing
const isNew = ref(false);
// Geometry bounds
const bounds = ref([90, 180, -90, -180]);
const bounds = ref([[0, 0], [0, 0]]);
// Phone number validation for each field
const isPocPhoneValid = ref(null);
const isDistribPhoneValid = ref(null);
Expand Down Expand Up @@ -712,14 +712,14 @@ export default defineComponent({
}
};
// Update the geometry of the form based on the bounding box editor input
const updateGeometry = (bbox) => {
if (bbox) {
model.value.origin.northLatitude = bbox.northLatitude;
model.value.origin.eastLongitude = bbox.eastLongitude;
model.value.origin.southLatitude = bbox.southLatitude;
model.value.origin.westLongitude = bbox.westLongitude;
}
// Update the rectangle in the map when the user changes the bounding box
const updateBbox = () => {
bounds.value = [
model.value.origin.northLatitude || 90,
model.value.origin.eastLongitude || -180,
model.value.origin.southLatitude || -90,
model.value.origin.westLongitude || 180
];
};
// Validates the phone numbers entered by the user
Expand Down Expand Up @@ -1017,14 +1017,19 @@ export default defineComponent({
}
});
// Also check if the formFilled value changes
// Also set the validation state to false if the formFilled value changes
watch(() => formFilled.value, (oldVal, newVal) => {
// Set metadataValidated.value to false whenever formFilled is changed
if (oldVal !== newVal) {
metadataValidated.value = false;
}
});
// Update the map when the user changes the bounding box
watch(() => deepClone(model.value.origin), () => {
updateBbox();
});
// Watch for the distributor checkbox to duplicate the contact info any time the POC information is changed
// Note that watchEffect is used here instead of watch, because it should re run whenever any reactive dependency changes
watchEffect(() => {
Expand All @@ -1051,7 +1056,6 @@ export default defineComponent({
languageCodeList,
countryCodeList,
isNew,
updateGeometry,
bounds,
isPocPhoneValid,
isDistribPhoneValid,
Expand Down

0 comments on commit a372c2a

Please sign in to comment.