feat(geolocation): add satellite view to input field

Added sattellite view on geolocation input field.
Added labels option and tarrain lines option in sattellite view.
move tail url and options in utils frappe.provide
This commit is contained in:
muhammedirfan Desk 2025-05-23 17:45:34 +05:30 committed by 0muhammedirfan-pc-wsl
parent d3a5e8d13e
commit ae264e2523
3 changed files with 206 additions and 42 deletions

View file

@ -47,6 +47,7 @@ frappe.ui.form.ControlGeolocation = class ControlGeolocation extends frappe.ui.f
if (!this.map) {
this.customize_draw_controls();
this.bind_leaflet_map();
this.bind_leaflet_layers_control();
}
if (this.disabled) {
this.map.dragging.disable();
@ -123,7 +124,7 @@ frappe.ui.form.ControlGeolocation = class ControlGeolocation extends frappe.ui.f
* @param {Object} feature - The leaflet object representing a geojson feature.
* @param {Object} layer - The leaflet layer object.
*/
on_each_feature(feature, layer) {}
on_each_feature(feature, layer) { }
customize_draw_controls() {
const circleToGeoJSON = L.Circle.prototype.toGeoJSON;
@ -156,13 +157,47 @@ frappe.ui.form.ControlGeolocation = class ControlGeolocation extends frappe.ui.f
this.map = L.map(this.map_id);
this.map.setView(frappe.utils.map_defaults.center, frappe.utils.map_defaults.zoom);
L.tileLayer(frappe.utils.map_defaults.tiles, frappe.utils.map_defaults.options).addTo(
this.map
this.streetLayer = L.tileLayer(
frappe.utils.map_defaults.tiles.defaultTile.url,
frappe.utils.map_defaults.tiles.defaultTile.options
);
this.satelliteLayer = L.tileLayer(
frappe.utils.map_defaults.tiles.sattelliteTail.url,
frappe.utils.map_defaults.tiles.sattelliteTail.options
);
this.labelsLayer = L.tileLayer(
frappe.utils.map_defaults.tiles.labelsTail.url,
frappe.utils.map_defaults.tiles.labelsTail.options
);
this.terrainLayer = L.tileLayer(
frappe.utils.map_defaults.tiles.terrainLinesTail.url,
frappe.utils.map_defaults.tiles.terrainLinesTail.options
);
this.streetLayer.addTo(this.map)
this.editableLayers = new L.FeatureGroup();
}
bind_leaflet_layers_control() {
// Add layers control for switching between map types
// Define base and overlay layers as properties of the class instance for access in other methods
const baseLayers = {
"Default": this.streetLayer,
"Satellite": this.satelliteLayer
};
const overlays = {
"Labels": this.labelsLayer,
"Terrain": this.terrainLayer
};
L.control.layers(baseLayers, overlays).addTo(this.map);
this.display_leaflet_overlays_control('none')
}
bind_leaflet_locate_control() {
// To request location update and set location, sets current geolocation on load
this.locate_control = L.control.locate({ position: "topright" });
@ -214,6 +249,17 @@ frappe.ui.form.ControlGeolocation = class ControlGeolocation extends frappe.ui.f
});
}
display_leaflet_overlays_control(display = '') {
const layerControlContainer = document.querySelector('.leaflet-control-layers-overlays');
const separator = document.querySelector('.leaflet-control-layers-separator');
if (layerControlContainer) {
layerControlContainer.style.display = display;
}
if (separator) {
separator.style.display = display;
}
}
bind_leaflet_event_listeners() {
this.bound_event_listeners = true;
this.map.on("draw:created", (e) => {
@ -231,6 +277,30 @@ frappe.ui.form.ControlGeolocation = class ControlGeolocation extends frappe.ui.f
this.editableLayers.removeLayer(layer);
this.set_value(JSON.stringify(this.editableLayers.toGeoJSON()));
});
// Remove overlays and overlays options when selecting the default view
this.map.on("baselayerchange", (e) => {
if (e.name === "Satellite") {
// Show overlays options and separator only in Satellite view
this.display_leaflet_overlays_control()
} else {
// Hide overlays options and separator in other views
this.display_leaflet_overlays_control('none')
// Remove all overlays
Object.values(this.map._layers).forEach(layer => {
if (
layer instanceof L.TileLayer &&
(
layer._url === frappe.utils.map_defaults.tiles.labelsTail.url ||
layer._url === frappe.utils.map_defaults.tiles.terrainLinesTail.url
)
) {
this.map.removeLayer(layer);
}
});
}
});
}
add_non_group_layers(source_layer, target_group) {

View file

@ -713,14 +713,14 @@ Object.assign(frappe.utils, {
var objPattern = new RegExp(
// Delimiters.
"(\\" +
strDelimiter +
"|\\r?\\n|\\r|^)" +
// Quoted fields.
'(?:"([^"]*(?:""[^"]*)*)"|' +
// Standard fields.
'([^"\\' +
strDelimiter +
"\\r\\n]*))",
strDelimiter +
"|\\r?\\n|\\r|^)" +
// Quoted fields.
'(?:"([^"]*(?:""[^"]*)*)"|' +
// Standard fields.
'([^"\\' +
strDelimiter +
"\\r\\n]*))",
"gi"
);
@ -1185,10 +1185,31 @@ Object.assign(frappe.utils, {
map_defaults: {
center: [19.08, 72.8961],
zoom: 13,
tiles: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
options: {
attribution:
'&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
tiles: {
defaultTile: {
url: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
options: {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
}
},
sattelliteTail: {
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
options: {
attribution: '© Esri © OpenStreetMap Contributors',
}
},
labelsTail: {
url: 'https://tiles.stadiamaps.com/tiles/stamen_toner_labels/{z}/{x}/{y}{r}.png',
options: {
attribution: '&copy; <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a> &copy; <a href="https://www.stamen.com/" target="_blank">Stamen Design</a> &copy; <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a>',
}
},
terrainLinesTail: {
url: 'https://tiles.stadiamaps.com/tiles/stamen_terrain_lines/{z}/{x}/{y}{r}.png',
options: {
attribution: '&copy; <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a> &copy; <a href="https://www.stamen.com/" target="_blank">Stamen Design</a> &copy; <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a>',
}
}
},
image_path: "/assets/frappe/images/leaflet/",
},
@ -1203,13 +1224,12 @@ Object.assign(frappe.utils, {
} else {
size_class = `icon-${size}`;
}
return `<svg class="${
is_espresso
? icon_name.startsWith("es-solid")
? "es-icon es-solid"
: "es-icon es-line"
: "icon"
} ${svg_class} ${size_class}" style="${icon_style}" aria-hidden="true">
return `<svg class="${is_espresso
? icon_name.startsWith("es-solid")
? "es-icon es-solid"
: "es-icon es-line"
: "icon"
} ${svg_class} ${size_class}" style="${icon_style}" aria-hidden="true">
<use class="${icon_class}" href="${icon_name}"></use>
</svg>`;
},
@ -1384,9 +1404,8 @@ Object.assign(frappe.utils, {
build_summary_item(summary) {
if (summary.type == "separator") {
return $(`<div class="summary-separator">
<div class="summary-value ${summary.color ? summary.color.toLowerCase() : "text-muted"}">${
summary.value
}</div>
<div class="summary-value ${summary.color ? summary.color.toLowerCase() : "text-muted"}">${summary.value
}</div>
</div>`);
}
let df = { fieldtype: summary.datatype };
@ -1400,8 +1419,8 @@ Object.assign(frappe.utils, {
let color = summary.indicator
? summary.indicator.toLowerCase()
: summary.color
? summary.color.toLowerCase()
: "";
? summary.color.toLowerCase()
: "";
return $(`<div class="summary-item">
<span class="summary-label">${__(summary.label)}</span>
@ -1413,17 +1432,17 @@ Object.assign(frappe.utils, {
let w = window.open(
frappe.urllib.get_full_url(
"/printview?doctype=" +
encodeURIComponent(doctype) +
"&name=" +
encodeURIComponent(docname) +
"&trigger_print=1" +
"&format=" +
encodeURIComponent(print_format) +
"&no_letterhead=" +
(letterhead ? "0" : "1") +
"&letterhead=" +
encodeURIComponent(letterhead) +
(lang_code ? "&_lang=" + lang_code : "")
encodeURIComponent(doctype) +
"&name=" +
encodeURIComponent(docname) +
"&trigger_print=1" +
"&format=" +
encodeURIComponent(print_format) +
"&no_letterhead=" +
(letterhead ? "0" : "1") +
"&letterhead=" +
encodeURIComponent(letterhead) +
(lang_code ? "&_lang=" + lang_code : "")
)
);
@ -1779,8 +1798,8 @@ Object.assign(frappe.utils, {
frappe.msgprint(
__("Tracking URL generated and copied to clipboard") +
": <br>" +
`<a href="${url}">${url.bold()}</a>`,
": <br>" +
`<a href="${url}">${url.bold()}</a>`,
__("Here's your tracking URL")
);
},

View file

@ -43,12 +43,31 @@ frappe.views.MapView = class MapView extends frappe.views.ListView {
frappe.utils.map_defaults.zoom
);
L.tileLayer(frappe.utils.map_defaults.tiles, frappe.utils.map_defaults.options).addTo(
this.map
this.streetLayer = L.tileLayer(
frappe.utils.map_defaults.tiles.defaultTile.url,
frappe.utils.map_defaults.tiles.defaultTile.options
);
this.satelliteLayer = L.tileLayer(
frappe.utils.map_defaults.tiles.sattelliteTail.url,
frappe.utils.map_defaults.tiles.sattelliteTail.options
);
this.labelsLayer = L.tileLayer(
frappe.utils.map_defaults.tiles.labelsTail.url,
frappe.utils.map_defaults.tiles.labelsTail.options
);
this.terrainLayer = L.tileLayer(
frappe.utils.map_defaults.tiles.terrainLinesTail.url,
frappe.utils.map_defaults.tiles.terrainLinesTail.options
);
this.streetLayer.addTo(this.map)
this.bind_leaflet_layers_control()
this.bind_leaflet_locate_control();
L.control.scale().addTo(this.map);
if (!this.bound_event_listeners) {
this.bind_leaflet_event_listeners();
}
}
render() {
@ -140,9 +159,65 @@ frappe.views.MapView = class MapView extends frappe.views.ListView {
}
}
bind_leaflet_layers_control() {
// Add layers control for switching between map types
// Define base and overlay layers as properties of the class instance for access in other methods
const baseLayers = {
"Default": this.streetLayer,
"Satellite": this.satelliteLayer
};
const overlays = {
"Labels": this.labelsLayer,
"Terrain": this.terrainLayer
};
L.control.layers(baseLayers, overlays).addTo(this.map);
this.display_leaflet_overlays_control('none')
}
bind_leaflet_locate_control() {
// To request location update and set location, sets current geolocation on load
this.locate_control = L.control.locate({ position: "topright" });
this.locate_control.addTo(this.map);
}
display_leaflet_overlays_control(display = '') {
const layerControlContainer = document.querySelector('.leaflet-control-layers-overlays');
const separator = document.querySelector('.leaflet-control-layers-separator');
if (layerControlContainer) {
layerControlContainer.style.display = display;
}
if (separator) {
separator.style.display = display;
}
}
bind_leaflet_event_listeners() {
this.bound_event_listeners = true;
// Remove overlays and overlays options when selecting the default view
this.map.on("baselayerchange", (e) => {
if (e.name === "Satellite") {
// Show overlays options and separator only in Satellite view
this.display_leaflet_overlays_control()
} else {
// Hide overlays options and separator in other views
this.display_leaflet_overlays_control('none')
// Remove all overlays
Object.values(this.map._layers).forEach(layer => {
if (
layer instanceof L.TileLayer &&
(
layer._url === frappe.utils.map_defaults.tiles.labelsTail.url ||
layer._url === frappe.utils.map_defaults.tiles.terrainLinesTail.url
)
) {
this.map.removeLayer(layer);
}
});
}
});
}
};