import { FilterUi } from "./FilterUi.js";
import { Map2D } from "../../Map2D.js";
import { debounceCallback, roundNumber } from "../../../utils/utils.js";
import "./BoundingBox.css";
export { BoundingBox };
/**
* Geographical filter for features within a bounding box.
* @memberof vef.map.filters.ui
*/
class BoundingBox extends FilterUi {
classname = "bounding-box-filter";
html = `
<div class="bounding-box-area">
<div class="bounding-box-west">West<br><input type="number"></div>
<div class="bounding-box-south">South<br><input type="number"></div>
<div class="bounding-box-east">East<br><input type="number"></div>
<div class="bounding-box-north">North<br><input type="number"></div>
</div>
<div class="bounding-box-button"><button class="edit_bbox">Edit on Map</button></div>`
;
/**
* @param {HTMLElement | string} target
* @param {object} options filter specific options
* @param {LayerCache} layers Used for included/excluded layers
* @param {Map} map
*/
constructor(target, options, layers, map) {
// apply default options
options = Object.assign({
title: "Bounding Box",
applyGlobalFilters: false,
showNullValues: true,
values: [-10, -10, 10, 10],
column: "",
}, options || {});
super(target, options, layers, map);
this.setClass("bounding-box-filter");
this.setContent(this.html);
this.setValues(this.options_.values);
// Buttons
this.query(".edit_bbox").addEventListener("click", () => this.drawOnMap());
this.queryAll("input").forEach(input => {
input.addEventListener("input", debounceCallback(() => this.apply(), 1000));
});
// apply at end of event loop, to wait until all filters are added in the viewer
setTimeout(() => this.apply(), 0);
}
drawOnMap() {
// use leaflet map directly instead of Map class, because rectangle drawing is not handled in vef
if (!(this.map instanceof Map2D)) return;
if (this.rectangle) {
this.rectangle.editing.disable();
this.rectangle.off();
this.rectangle.remove();
this.rectangle = null;
this.query(".edit_bbox").innerText = "Edit on Map";
return;
}
const style = window.getComputedStyle(document.body);
this.rectangle = L.rectangle(this.getLeafletBbox(), {
color: style.getPropertyValue("--primary-color")
});
this.rectangle.on('edit', () => {
const bounds = this.rectangle.getBounds();
this.options_.values = [bounds.getWest(), bounds.getSouth(), bounds.getEast(), bounds.getNorth()];
this.setValues(this.options_.values);
});
this.rectangle.editing.enable();
const map = this.map.leafletMap_;
map.addLayer(this.rectangle);
this.query(".edit_bbox").innerText = "Stop Editing on Map";
}
getLeafletBbox() {
const bbox = this.options_.values;
return [[bbox[1], bbox[0]], [bbox[3], bbox[2]]];
}
/**
* @param {number[]} values [West, South, East, North]
*/
setValues(values) {
const inputs = this.queryAll("input");
for (let index = 0; index <= 3; index++) {
inputs[index].value = roundNumber(values[index], 3, false);
}
this.fire("change", this);
}
getValuesChange() {
const arr = [];
const inputs = this.queryAll("input");
for (let index = 0; index < inputs.length; index++) {
arr[index] = inputs[index].value.trim();
arr[index] = parseInt(arr[index])
}
return arr;
}
getActiveFilter() {
const values = this.options_.values;
return {
type: "geometry",
column: this.options_.column,
values: [["bbox", values[1], values[0], values[3], values[2]]],
excludedLayers: this.getExcludedLayers()
}
}
apply() {
this.options_.values = this.getValuesChange();
if (this.rectangle) {
this.rectangle.editing.disable();
this.rectangle.setBounds(this.getLeafletBbox());
this.rectangle.editing.enable();
}
this.fire("change", this);
}
}