Scriptcase is a PHP web development tool that makes the development of web applications easier and faster, especially for users like me with limited experience and in depth knowledge of programming. Among many others it offers an option to create controls that can be customized to serve the needed role in the context of the application and are not necessarily bound to the database of the application.
Since many of the data I am dealing with have a spatial reference to geographical locations as points, I wanted to work around a way to use Google basemaps (especially the satellite ones) to be able to add and edit existing locations. These locations in my case are a pair of coordinates in decimal degrees in the WGS 84 coordinate system (EPSG:4326) stored in two separate fields (of double precision, or float8 – float4 field types) londd for the decimal degrees longitude and latdd fot the decimal degrees latitude. In some cases these double precision fields are translated to spatial enabled fields that can readily be plotted to gis software like QGIS and ArcGIS. In this example the database is a Postgres database with the ESRI SDE spatial extension enabled that stores the spatial points in a field called shape and in another case of Postgresql database with Postgis extension enabled the spatial field name is geometry. In both these cases with the Postgis and ArcGIS SDE extensions simple spatial queries are executed which updates other spatial related info, like the district, the prefecture, the island name etc in which the point falls within. This helps the user with the update process making it faster and eliminates the possibility of an error of the updating of the mentioned spatial related fields.
Before update Postgresql with ArcGIS SDE extension enabled trigger function
BEGIN
IF (st_x(NEW.shape)<>st_x(OLD.shape)) OR (st_y(NEW.shape)<>st_y(OLD.shape)) THEN
NEW.periferia_id = (SELECT periferies_new.objectid
from sde.periferies_new, sde.bats_locations
where st_contains (periferies_new.shape, bats_locations.shape) = 't'
and bats_locations.objectid = NEW.objectid);
NEW.nomos_id = (SELECT nomoi.objectid
from sde.nomoi, sde.bats_locations
where st_contains (nomoi.shape, bats_locations.shape) = 't'
and bats_locations.objectid = NEW.objectid);
NEW.island_id = (SELECT coast_withnames.objectid
from sde.coast_withnames, sde.bats_locations
where st_contains (coast_withnames.shape, bats_locations.shape) = 't'
and bats_locations.objectid = NEW.objectid);
END IF;
NEW.update_date = now();
RETURN NEW;
END
Index.html
<html>
<head>
<!--SC_PAGE_CHARSET-->
<!--SC_JS_LIB-->
<link rel="stylesheet" type="text/css" href="{SC_LIB_CURRENT}/css/bootstrap/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="{SC_LIB_CURRENT}/css/controlpoints.css" />
<script type="text/javascript" src="{SC_LIB_CURRENT}/js/bootstrap/bootstrap.min.js"></script>
<script type="text/javascript" src="{SC_LIB_CURRENT}/js/controlpoints.js"></script>
<title><!--SC_PAGE_TITLE--></title>
</head>
<body>
<div class="row">
<div class="col-12 col-sm-6 col-md-8">
<div id="map">
<div style="width: 100%; height: 100%; " id="map"></div>
<div id="content-window"> </div>
</div>
</div>
<div class="col-6 col-md-4">
<form {SC_FORM_ATTR}>
<!--SC_FORM_HIDDEN-->
<!--SC_FIELD_LABEL_my_field-->
<br />
<input {SC_FIELD_INFO_idlocality} class="form-control {SC_FIELD_CLASS}" type="text" />
<div class="coords">
<div class="coord">
<span class="label">Longitude</span>
<input {SC_FIELD_INFO_londd} class="form-control {SC_FIELD_CLASS}" type="text" />
</div>
<div class="coord">
<span class="label">Latitude</span>
<input {SC_FIELD_INFO_latdd} class="form-control {SC_FIELD_CLASS}" type="text" />
</div>
<div class="coord submitbutton">
<input type="submit" {SC_FORM_SUBMIT_INFO} />
</div>
</div>
</form>
<button onclick="resetPoint()">Reset Position</button>
<button id="closewindow">Cancel / Exit</button>
<div id="location-info">
<h2>Existing location information</h2>
<div class="location-info idlocation">
<span class="label-info">GIS ID</span>
<input {SC_FIELD_INFO_gisid} class="form-control {SC_FIELD_CLASS}" type="text" readonly="readonly" />
</div>
<div class="location-info">
<span class="label-info">District</span>
<input {SC_FIELD_INFO_periferia} class="form-control {SC_FIELD_CLASS}" type="text" readonly="readonly" />
</div>
<div class="location-info">
<span class="label-info">Perfecture</span>
<input {SC_FIELD_INFO_nomos} class="form-control {SC_FIELD_CLASS}" type="text" readonly="readonly" />
</div>
<div class="location-info">
<span class="label-info">Island name</span>
<input {SC_FIELD_INFO_island_name} class="form-control {SC_FIELD_CLASS}" type="text" readonly="readonly" />
</div>
<div class="location-info">
<span class="label-info">Area</span>
<input {SC_FIELD_INFO_area} class="form-control {SC_FIELD_CLASS}" type="text" readonly="readonly" />
</div>
<div class="location-info">
<span class="label-info">Location name</span>
<input {SC_FIELD_INFO_location} class="form-control {SC_FIELD_CLASS}" type="text" readonly="readonly" />
</div>
<div class="location-info">
<span class="label-info">Update date / time</span>
<input {SC_FIELD_INFO_update_date} class="form-control {SC_FIELD_CLASS}" type="text" readonly="readonly" />
</div>
</div>
</div>
</div>
<!-- This contains the hidden content for inline calls -->
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_HERE&callback=initMap">
</script>
</body>
</html>
controlpoints.js
var marker;
// Initial coordinates from the parent form
var thelon;
var thelat;
// New coordinates given from the map or disrectly from the input coordinate fields
var newlon;
var newlat;
window.map = undefined; // global variable
function scDisplayUserError(errorMessage) {
alert("ERROR\r\n" + errorMessage.replace(/<br \/>/gi, "\n"));
}
function scDisplayUserDebug(debugMessage) {
alert("DEBUG\r\n" + debugMessage.replace(/<br \/>/gi, "\n"));
}function scDisplayUserMessage(userMessage) {
alert("MESSAGE\r\n" + userMessage.replace(/<br \/>/gi, "\n"));
}
// This will reset the coordinates to the initial values. This is an alternative to reexamine the initial position of the point without closing and reopening the control
function resetPoint() {
// Set the values of the coordinates from the parent form
thelon=parseFloat(parent.document.getElementById("id_sc_field_londd_manual").value);
thelat=parseFloat(parent.document.getElementById("id_sc_field_latdd_manual").value);
// Assign the values to the respective input fields of the iframe control form
document.getElementById("id_sc_field_londd").value=thelon;
document.getElementById("id_sc_field_latdd").value=thelat;
// Reset the center of the map and the marker position
const center = new google.maps.LatLng(thelat, thelon);
window.map.panTo(center);
marker.setPosition( new google.maps.LatLng( thelat, thelon ) );
}
function initMap() {
// Set initial coordinates values from parent form
thelon = parseFloat(parent.document.getElementById("id_sc_field_londd_manual").value);
thelat = parseFloat(parent.document.getElementById("id_sc_field_latdd_manual").value);
document.getElementById('id_sc_field_londd').value = thelon;
document.getElementById('id_sc_field_latdd').value = thelat;
var myLatLng = {lat: thelat, lng: thelon};
// Starting parameters for the map by setting a default zoom and centering at the location of the marker
window.map = new google.maps.Map(document.getElementById('map'), {
zoom: 11,
center: myLatLng
});
pointLatLng = new google.maps.LatLng({lat: thelat, lng: thelon});
marker = new google.maps.Marker({
position: myLatLng,
map: map,
position: pointLatLng,
draggable: true,
title: 'Custom point'
});
<!-- Move the marker by dragging it -->
marker.addListener('dragend', function(evt) {
console.log('Lat: ' + evt.latLng.lat() + ' Lon: ' + evt.latLng.lng());
newlon=parseFloat((Math.round(evt.latLng.lng() * 10000000) / 10000000).toFixed(7));
newlat=parseFloat((Math.round(evt.latLng.lat() * 10000000) / 10000000).toFixed(7));
document.getElementById('id_sc_field_londd').value = newlon;
document.getElementById('id_sc_field_latdd').value = newlat;
});
<!-- On single click move the marker -->
google.maps.event.addListener(map, 'click', function(evt) {
newlon=parseFloat((Math.round(evt.latLng.lng() * 10000000) / 10000000).toFixed(7));
newlat=parseFloat((Math.round(evt.latLng.lat() * 10000000) / 10000000).toFixed(7));
const center = new google.maps.LatLng(newlat, newlon);
window.map.panTo(center);
marker.setPosition( new google.maps.LatLng( newlat, newlon ) );
document.getElementById('id_sc_field_londd').value = newlon;
document.getElementById('id_sc_field_latdd').value = newlat;
});
}
$(document).ready(function () {
$('#closewindow').click(function (){
$('#TB_overlay', window.parent.document).remove();
$('#TB_window', window.parent.document).remove();
});
});
function exitModal() {
parent.document.getElementById('id_sc_field_londd_manual').value = newlon;
parent.document.getElementById('id_sc_field_latdd_manual').value = newlat;
$('#TB_overlay', window.parent.document).remove();
$('#TB_window', window.parent.document).remove();
}
// Ajax executed function on coordinate fields change
function coordinatesChanged(thelon,thelat) {
newlon=thelon;
newlat=thelat;
document.getElementById("id_sc_field_londd").value=thelon;
document.getElementById("id_sc_field_latdd").value=thelat;
const center = new google.maps.LatLng(thelat, thelon);
window.map.panTo(center);
marker.setPosition( new google.maps.LatLng( thelat, thelon ) );
}