forked from geolba/tethys.frontend
101 lines
No EOL
3.6 KiB
TypeScript
101 lines
No EOL
3.6 KiB
TypeScript
import { Component, Prop, Vue } from 'vue-facing-decorator';
|
|
import * as L from 'leaflet';
|
|
import 'leaflet/dist/leaflet.css';
|
|
|
|
@Component({
|
|
name: 'Minimap',
|
|
})
|
|
export default class Minimap extends Vue {
|
|
@Prop({ type: Array, required: true }) bounds!: L.LatLngBoundsLiteral;
|
|
|
|
// private originalCenter: L.LatLngExpression = [47.71, 13.55]; // Original center
|
|
// private originalZoom: number = 6; // Original zoom level
|
|
|
|
mounted() {
|
|
const map = L.map('map', {
|
|
center: [47.71, 13.55],
|
|
zoomControl: true,
|
|
zoom: 6,
|
|
minZoom: 5,
|
|
maxBounds: [
|
|
[44.0, 9.0], // Southwest corner of the bounds
|
|
[51.0, 18.0] // Northeast corner of the bounds
|
|
],
|
|
maxBoundsViscosity: 1.0 // Ensure the map cannot be dragged outside the bounds
|
|
});
|
|
|
|
// Remove Leaflet logo and text
|
|
map.attributionControl.setPrefix(false);
|
|
|
|
const basemapAtLayer = L.tileLayer('https://maps{s}.wien.gv.at/basemap/geolandbasemap/normal/google3857/{z}/{y}/{x}.png', {
|
|
attribution: '<a href="https://www.basemap.at">basemap.at</a>',
|
|
noWrap: true,
|
|
subdomains: ['', '1', '2', '3', '4']
|
|
}).addTo(map);
|
|
|
|
const esriImageryLayer = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
|
|
attribution: 'Tiles © <a href="https://www.esri.com/" target="_blank">Esri</a>'
|
|
});
|
|
|
|
const esriTopoLayer = L.tileLayer('https://server.arcgisonline.com/arcgis/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}', {
|
|
attribution: 'Tiles © <a href="https://www.esri.com/" target="_blank">Esri</a>'
|
|
});
|
|
|
|
const baseMaps = {
|
|
// "OpenStreetMap": openStreetMapLayer,
|
|
"basemap.at": basemapAtLayer,
|
|
"ESRI Imagery": esriImageryLayer,
|
|
"ESRI Topo": esriTopoLayer
|
|
};
|
|
|
|
L.control.layers(baseMaps).addTo(map);
|
|
|
|
const [southWest, northEast] = this.bounds;
|
|
|
|
if (southWest[0] === northEast[0] || southWest[1] === northEast[1]) {
|
|
// If y_min and y_max (and x_min and x_max) are equal, generate a circle
|
|
const center = [southWest[0], southWest[1]] as [number, number];
|
|
// Using CircleMarker to maintain constant size regardless of zoom level
|
|
const circleMarker = L.circleMarker(center, {
|
|
color: '#30D5C8', // Outline color
|
|
fillColor: '#336699', // Fill color
|
|
fillOpacity: 1, // Opacity of the fill
|
|
opacity: 0.5, // Outline opacity
|
|
weight: 10, // Outline weight
|
|
radius: 10 // Radius in pixels
|
|
}).addTo(map);
|
|
|
|
// Manually create a small bounding box around the marker's center to fit bounds
|
|
const buffer = 0.01; // Adjust this value to control the area around the marker
|
|
const markerBounds = L.latLngBounds(
|
|
[center[0] - buffer, center[1] - buffer], // Southwest corner
|
|
[center[0] + buffer, center[1] + buffer] // Northeast corner
|
|
);
|
|
|
|
|
|
// Add a click event to the CircleMarker
|
|
circleMarker.on('click', () => {
|
|
map.fitBounds(markerBounds, { padding: [10, 10] });
|
|
});
|
|
|
|
map.fitBounds(markerBounds, { padding: [10, 10] });
|
|
|
|
} else {
|
|
// Otherwise, generate a rectangle
|
|
const rectangle = L.rectangle(this.bounds, {
|
|
color: '#30D5C8',
|
|
weight: 2,
|
|
opacity: 1
|
|
}).addTo(map); //336699
|
|
|
|
// Add a click event to the Rectangle
|
|
rectangle.on('click', () => {
|
|
map.fitBounds(this.bounds, { padding: [18, 18] });
|
|
});
|
|
|
|
// Fit the map's view to the rectangle's bounds with padding
|
|
map.fitBounds(this.bounds, { padding: [18, 18] });
|
|
}
|
|
}
|
|
|
|
} |