schedule/lib/scheduleCitiesMap.js
2023-10-13 06:43:02 +02:00

601 lines
19 KiB
JavaScript

/*
All scheduleMap behaviors managed by schedule plugin
scheduleMapList: Map of
mapId => scheduleMap
scheduleMap
mapId: div map ID
map: map
poi: Point Of Interest
poiSize: # of number
clusterLayer: clusterLayer
*/
var scheduleMapList = {};
var scheduleUseMap = JSINFO['schedule']['useMap'];
var scheduleZoom = JSINFO['schedule']['defaultZoom'];
var scheduleCenter = JSINFO['schedule']['defaultCenter'];
var schedulePoiUri = DOKU_BASE+'lib/plugins/schedule/images/poi.png';
var scheduleSelectedPoiUri = DOKU_BASE+'lib/plugins/schedule/images/poiRed.png';
var scheduleEmptyUri = DOKU_BASE+'lib/plugins/schedule/images/empty.png';
var scheduleIconCalendarUri = DOKU_BASE+'lib/plugins/schedule/images/calendar.png';
var scheduleAjaxPoiUri = DOKU_BASE+"lib/plugins/schedule/ajaxPOI.php";
var schedulePrecision = 5;
var locationFormatRE = new RegExp ("^\\s*\\(\\s*([\\-0-9.]+)\\s*\\|\\s*([\\-0-9.]+)\\s*\\)\\s*(.*)$");
var iconStyle;
var iconSelectedStyle;
/* selected LI on city UL */
var scheduleSelectedCity = null;
// ========================================
/* format location */
function scheduleGetLocation (lat, lon) {
return "("+
parseFloat (parseFloat (lat).toFixed (schedulePrecision))+"|"+
parseFloat (parseFloat (lon).toFixed (schedulePrecision))+")";
}
// ========================================
/* convert and reverse location */
function scheduleGetCoordFromLocation (latLonArray) {
return ol.proj.transform ([latLonArray [1], latLonArray [0]], 'EPSG:4326', 'EPSG:3857');
}
// ========================================
/* convert and reverse location */
function scheduleGetLocationFromCoord (coord) {
var lonLat = ol.proj.transform (coord, 'EPSG:3857', 'EPSG:4326');
return [parseFloat (lonLat[1]).toFixed (schedulePrecision), parseFloat (lonLat [0]).toFixed (schedulePrecision)];
}
// ========================================
/* center scheduleMap according POI markers */
function scheduleCenterMap (scheduleMap) {
if (!scheduleUseMap)
return;
if (scheduleMap.poiSize) {
scheduleMap.map.getView ().fit (scheduleMap.poi.getExtent (), scheduleMap.map.getSize ());
scheduleMap.map.getView ().setZoom (Math.min (scheduleMap.map.getView ().getZoom ()*.9,
scheduleZoom));
return;
}
scheduleMap.map.getView ().setCenter (scheduleGetCoordFromLocation (scheduleCenter));
scheduleMap.map.getView ().setZoom (6); //scheduleZoom);
}
// ========================================
/* remove all POI markers */
function scheduleClearMarkers (scheduleMap) {
if (!scheduleUseMap)
return;
scheduleMap.poiSize = 0;
if (scheduleMap.poi !== undefined)
scheduleMap.poi.clear ();
}
// ========================================
/* add a wellknown city marker */
function scheduleAddCityMarker (scheduleMap, cityCode) {
if (! cityCode)
return;
var inseeLocation = inseeCityNameLatLon[cityCode];
if (!style) {
// XXX not found
return;
}
scheduleAddLatLonCityMarker (scheduleMap, cityCode,
inseeCityNameLatLon[cityCode][1],
inseeCityNameLatLon[cityCode][2]);
}
// ========================================
/* add a positioned city marker */
function scheduleAddLatLonCityMarker (scheduleMap, cityCode, lat, lon) {
if (!scheduleUseMap)
return;
scheduleMap.poiSize++;
if (scheduleMap.poi === undefined)
return;
scheduleMap.poi.addFeature (new ol.Feature({
geometry: new ol.geom.Point (scheduleGetCoordFromLocation ([lat, lon])),
cityCode: cityCode,
location: scheduleGetLocation (lat, lon),
lat: lat,
lon: lon,
selected: false
}));
}
// ========================================
/* highlight all cities on the list of adress */
function scheduleHighlightAddress (locations) {
if (!locations) {
jQuery ('div.scheduleAddresse').removeClass("poiAdrLight");
return;
}
jQuery ('div.scheduleAddresse').each (function () {
var adrBlock = jQuery (this);
var location = adrBlock.attr ('location');
if (location && (','+locations).indexOf (location) >= 0)
adrBlock.addClass("poiAdrLight");
else
adrBlock.removeClass("poiAdrLight");
});
}
function scheduleHighlightLocation (location) {
scheduleHighlightAddress (location);
scheduleHighlightPOI (location);
}
// ========================================
/* display cities from a UL */
function scheduleAddAllCityFromUl (scheduleMap, ul) {
scheduleClearMarkers (scheduleMap);
ul.find ('li').each (function (index) {
var li = jQuery (this);
scheduleAddLatLonCityMarker (scheduleMap, li.attr ('insee'),
li.attr ('lat'), li.attr ('lon'));
});
if (!scheduleUseMap)
return;
if (scheduleMap.poi !== undefined){
scheduleMap.poi.changed ();
scheduleMap.map.render ();
}
}
// ========================================
function scheduleAddCityToUl (ul, cityName) {
var cityCode = /[0-9AB]{5,}/.exec (cityName);
var lat = "";
var lon = "";
if (cityCode != null)
cityCode = cityCode[0];
if (!cityCode)
cityCode = inseeCityNameInsee [cityName.toLowerCase ()];
if (!cityCode)
cityName = cityCode = cityName.replace(/[^A-ZÀÂÆÇÉÈÊËÎÏÑÔŒÙÛÜÿ a-zàâæçéèêëîïñôœùûüÿ'\-]/gi,'');
else {
cityName = inseeCityNameLatLon[cityCode][0];
lat = inseeCityNameLatLon[cityCode][1];
lon = inseeCityNameLatLon[cityCode][2];
}
var recorded = false;
ul.find ('li[insee="'+cityCode+'"][lat="'+lat+'"][lon="'+lon+'"]').each (function (index) {
recorded = true;
scheduleSetSelectCity (jQuery (this));
});
if (recorded)
return;
var lonLat =
(lat && lon) ?
' lat="'+lat+'" lon="'+lon+'"' :
' class="unknown"';
ul.append ('<li insee="'+cityCode+'"'+lonLat+' onclick="scheduleSelectCity (this)">'+
'<img class="checked" src="'+scheduleEmptyUri+'" width="10" height="16" onclick="scheduleRemoveCity (this)"/>'+
' <span class="addresse"></span> '+
'<span class="city">'+cityName+'</span></li>');
scheduleSetSelectCity (ul.find ("li").last ());
}
// ========================================
/* Sort UL by city name (XXX what about addresse ?) */
function scheduleSortUlCities (ul) {
ul.children ('li').sort (function (a, b) {
var upa = jQuery (a).find ('span.city').text ().toUpperCase ();
var upb = jQuery (b).find ('span.city').text ().toUpperCase ();
return (upa < upb) ? -1 : (upa > upb) ? 1 : 0;
}).appendTo (ul[0]);
}
function scheduleAjaxPOILine (action) {
if (!scheduleSelectedCity)
// XXX dire quelque chose
return;
var insee = scheduleSelectedCity.attr ('insee');
var lat = scheduleSelectedCity.attr ('lat');
var lon = scheduleSelectedCity.attr ('lon');
var addr = scheduleSelectedCity.find ('span.addresse').html ().replace (/<br>/gi, '~br~');
line = new Array ();
line.push (insee);
line.push (lat);
line.push (lon);
line.push (addr);
jQuery.ajax ({
type: "POST",
url: scheduleAjaxPoiUri,
cache: true,
async: true,
data: { action: action, line: line.join ('|') },
success: function (response) { alert (response); }
});
}
function scheduleAddInsee () {
scheduleAjaxPOILine ("add");
}
function scheduleRemoveInsee () {
scheduleAjaxPOILine ("remove");
}
function scheduleTestInsee () {
}
function scheduleSetSelectCity (li) {
scheduleSelectedCity = li;
// change autocomplete
var cityCode = scheduleSelectedCity.attr ('insee');
var form = scheduleSelectedCity.closest ('.scheduleCitiesForm');
var input = form.find ('input[name="addr"]');
input. val (scheduleSelectedCity.find ('span.addresse').html ().replace (/<br>/gi, '~br~'));
jQuery.ajax ({
type: "POST",
url: scheduleAjaxPoiUri,
cache: true,
async: true,
data: { action: "list", insee: cityCode },
success: function (response) {
var db = jQuery.parseJSON (response);
source = new Array ();
for (var i = 0; i < db.length; i++) {
var vals = db[i].split ("|");
source.push ("("+vals[0]+"|"+vals[1]+") "+vals[2]);
}
input.autocomplete ({ source: source });
}
});
}
function scheduleFocusCity () {
if (!scheduleUseMap)
return;
var form = scheduleSelectedCity.closest ('.scheduleCitiesForm');
// focus on map
form.find ('.scheduleMap').each (function () {
var scheduleMap = scheduleMapList [jQuery (this).attr ('id')];
scheduleMap.map.getView ().setCenter (scheduleGetCoordFromLocation ([scheduleSelectedCity.attr ('lat'), scheduleSelectedCity.attr ('lon')]));
scheduleMap.map.getView ().setZoom (Math.min (scheduleMap.map.getView ().getZoom (), scheduleZoom));
});
}
// ========================================
/* User LI selection and focus on map */
function scheduleSelectCity (item) {
scheduleSetSelectCity (jQuery (item).closest ('li'));
scheduleFocusCity ();
}
// ========================================
/* User remove LI */
function scheduleRemoveCity (item) {
var li = jQuery (item).closest ('li');
var ul = li.closest ('ul');
li.remove ();
scheduleUpdateUlCity (ul);
}
function scheduleUpdateUlCity (ul) {
ul.closest ('.scheduleCitiesForm'). find ('.scheduleMap').each (function () {
var scheduleMap = scheduleMapList [jQuery (this).attr ('id')];
scheduleAddAllCityFromUl (scheduleMap, ul);
scheduleCenterMap (scheduleMap);
});
scheduleCheckInputs ();
}
// ========================================
/* Find all initial values */
function scheduleInitPOI () {
jQuery ('.schedulePOI').each (function () {
var poiDiv = jQuery (this);
var scheduleMap = scheduleMapList [poiDiv.find ('.scheduleMap').attr ('id')];
scheduleClearMarkers (scheduleMap);
poiDiv.find ('span.poiLocations').each (function () {
var poiLocations = jQuery (this).text ().split (',');
for (var i = 0; i < poiLocations.length; i++) {
var latLon = poiLocations[i];
var match = latLon.match (locationFormatRE);
if (match) {
var lat = parseFloat (match [1]).toFixed (schedulePrecision);
var lon = parseFloat (match [2]).toFixed (schedulePrecision);
scheduleAddLatLonCityMarker (scheduleMap, "", lat, lon);
} else
// cityCode = latLon
scheduleAddCityMarker (scheduleMap, latLon);
}
scheduleCenterMap (scheduleMap);
});
poiDiv.find ('ul.poiLatLon').each (function () {
jQuery (this).find ('li').each (function (index) {
var li = jQuery (this);
scheduleAddLatLonCityMarker (scheduleMap, li.text (),
li.attr ('lat'), li.attr ('lon'));
});
scheduleCenterMap (scheduleMap);
});
});
jQuery ('.scheduleCitiesForm').each (function () {
var scheduleCitiesForm = jQuery (this);
var scheduleMapDiv = scheduleCitiesForm.find ('.scheduleMap');
if (scheduleMapDiv[0] === undefined)
return;
var scheduleMap = scheduleMapList [scheduleMapDiv.attr ('id')];
scheduleAddAllCityFromUl (scheduleMap, jQuery (this).find ('.cities'));
scheduleCenterMap (scheduleMap);
});
}
// ========================================
/* Find all maps */
function scheduleInitMaps () {
if (!scheduleUseMap)
return;
jQuery ('.scheduleMap').each (function () {
var mapDiv = jQuery (this).find ('div');
if (mapDiv !== undefined && mapDiv && mapDiv.length)
return;
var mapId = jQuery (this).attr ('id');
var osm = new ol.layer.Tile ({
source: new ol.source.OSM ()
});
var poi = new ol.source.Vector ({
features: []
});
iconStyle = new ol.style.Style ({
image: new ol.style.Icon (/** @type {olx.style.IconOptions} */ ({
anchor: [.5, 1],
anchorXUnits: 'fraction',
anchorYUnits: 'fraction',
opacity: 0.75,
src: schedulePoiUri
}))
});
iconSelectedStyle = new ol.style.Style ({
image: new ol.style.Icon (/** @type {olx.style.IconOptions} */ ({
anchor: [.5, 1],
anchorXUnits: 'fraction',
anchorYUnits: 'fraction',
opacity: 0.75,
src: scheduleSelectedPoiUri
}))
});
var clusters = new ol.source.Cluster({
distance: 10,
source: poi,
});
var styleCache = {false: {}, true: {}};
var clusterLayer = new ol.layer.Vector({
source: clusters,
style: function (feature) {
var features = feature.get ('features');
var size = features.length;
if (size < 2)
return features [0].get ('selected') ? iconSelectedStyle : iconStyle;
var selected = false;
features.forEach (function (item) {
if (item.get ('selected'))
selected = true;
});
var style = styleCache[selected][size];
if (!style) {
style = [new ol.style.Style({
image: new ol.style.Icon (/** @type {olx.style.IconOptions} */ ({
anchor: [.5, 1],
anchorXUnits: 'fraction',
anchorYUnits: 'fraction',
opacity: 0.75,
src: selected ? scheduleSelectedPoiUri : schedulePoiUri
})),
text: new ol.style.Text({
text: size.toString (),
offsetY: -24 // XXX textpos conf ?
})
})];
styleCache[selected][size] = style;
}
return style;
}
});
var map = new ol.Map ({
target: mapId,
layers: [osm, clusterLayer],
//logo: false,
controls: ol.control.defaults ({
zoom: true,
attribution: false,
rotate: false
}),
view: new ol.View ({
center: ol.proj.fromLonLat (scheduleCenter),
zoom: scheduleZoom
})
});
if (jQuery (this).hasClass ("scheduleMapDisplay"))
map.set ("mapType", "display");
if (jQuery (this).hasClass ("scheduleMapForm"))
map.set ("mapType", "form");
if (jQuery (this).hasClass ("scheduleMapCalendar"))
map.set ("mapType", "calendar");
map.on ("singleclick", function (evt) {
var f;
map.forEachFeatureAtPixel (evt.pixel, function (feature) {
f = feature;
return true;
});
switch (map.get ("mapType")) {
case "display":
if (f) {
if (f.get ('features').length)
f = f.get ('features')[0];
window.open ("https://www.openstreetmap.org/?mlat="+f.get ('lat')+"&mlon="+f.get ('lon')+"&zoom="+scheduleZoom, "_self");
}
break;
case "form":
var location = scheduleGetLocationFromCoord (evt.coordinate);
scheduleSelectedCity.attr ('lat', location[0]);
scheduleSelectedCity.attr ('lon', location[1]);
scheduleAddAllCityFromUl (scheduleMap, scheduleSelectedCity.closest ('ul'));
break;
}
});
map.on ("pointermove", function (evt) {
var locations = new Set ();
map.forEachFeatureAtPixel (evt.pixel, function (feature) {
feature.get ('features').forEach (function (item) {
locations.add (item.get ('location'));
});
});
locations = Array.from (locations);
scheduleHighlightDays (locations);
scheduleHighlightLocation (locations.join (','));
});
var scheduleMap = {
mapId: mapId,
map: map,
poiSize: 0,
poi: poi,
clusterLayer: clusterLayer
};
scheduleMapList[mapId] = scheduleMap;
scheduleCenterMap (scheduleMap);
});
}
// ========================================
/* Initialisation and attach function */
jQuery (function () {
jQuery (function () {
// create tabs before OpenLayers stuff (important !)
jQuery (".scheduleTabForm").tabs ({
active: 0
});
jQuery ("#scheduleHelp").accordion ({
collapsible: true,
animated: false,
active: false
});
jQuery.datepicker.setDefaults ({
showOn: "both",
buttonImageOnly: true,
buttonImage: scheduleIconCalendarUri,
buttonText: "",
firstDay: 0
});
jQuery.datepicker.formatDate ("yy-mm-dd");
jQuery (".scheduleTabForm .date").datepicker ();
divError = jQuery ("div.schedule").prev ("div.error");
if (divError !== undefined && divError && divError.length)
// XXX a tester (avant divError.size ())
scheduleForceCheckInputs ();
});
// check and format form request
jQuery ('.scheduleFinalForm').submit (function () {
var scheduleFinalForm = jQuery (this);
if (!scheduleForceCheckInputs ())
return false;
var scheduleForm = scheduleFinalForm.closest ('.scheduleTabForm');
var scheduleCitiesForm = scheduleForm.find ('.scheduleCitiesForm');
var cities = new Array ();
var lats = new Array ();
var lons = new Array ();
var addrs = new Array ();
scheduleCitiesForm.find ('li').each (function (index) {
var li = jQuery (this);
cities.push (li.attr ('insee'));
lats.push (li.attr ('lat'));
lons.push (li.attr ('lon'));
addrs.push (li.find ('span.addresse').html ());
});
scheduleFinalForm.append ('<input type="hidden" name="schd[where]" value="'+cities.join (",")+'"/>');
scheduleFinalForm.append ('<input type="hidden" name="schd[lat]" value="'+lats.join (",")+'"/>');
scheduleFinalForm.append ('<input type="hidden" name="schd[lon]" value="'+lons.join (",")+'"/>');
scheduleFinalForm.append ('<input type="hidden" name="schd[addr]" value="'+addrs.join ("|").replace (/<br>/gi, '~br~')+'"/>');
var scheduleMiscForm = scheduleForm.find ('.scheduleMiscForm');
scheduleMiscForm.find ('input[type="text"]').each (function (index) {
if (this.value)
scheduleFinalForm.append ('<input type="hidden" name="'+this.name+'" value="'+this.value.replace(/"/gi, "''")+'"/>');
});
scheduleMiscForm.find ('select:not([class="members"])').each (function (index) {
scheduleFinalForm.append ('<input type="hidden" name="'+this.name+'" value="'+this.value+'"/>');
});
var members = new Array ();
scheduleMiscForm.find ('select[class="members"]').each (function (index) {
jQuery (this).find ('option:selected').each (function (index) {
members.push (jQuery (this).val ());
});
});
if (members.length > 0)
scheduleFinalForm.append ('<input type="hidden" name="schd[member]" value="'+members.join (",")+'"/>');
scheduleMiscForm.find ('textarea').each (function (index) {
var val = jQuery (this).val ().replace(/"/gi, "''");
var name = jQuery (this).attr ('name');
scheduleFinalForm.append ('<input type="hidden" name="'+name+'" value="'+val+'"/>');
});
return true;
});
// city validation
jQuery ('.scheduleCitiesForm input[name="city"]').keypress (function (e) {
if (e.which != 13)
return;
var input = jQuery (this);
var form = input.closest ('.scheduleCitiesForm');
var cityName = input.val ();
if (!cityName)
return false;
input.val ("");
form.find ('input[name="addr"]').val ("");
var ul = form.find ('ul');
scheduleAddCityToUl (ul, cityName);
scheduleSortUlCities (ul);
scheduleUpdateUlCity (ul);
return false;
});
// full adress validation
jQuery ('.scheduleCitiesForm input[name="addr"]').keypress (function (e) {
if (e.which != 13)
return;
if (!scheduleSelectedCity)
return;
var input = jQuery (this);
var form = input.closest ('.scheduleCitiesForm');
var addr = input.val ();
var match = addr.match (locationFormatRE);
if (match) {
addr = match [3];
scheduleSelectedCity.attr ('lat', parseFloat (match [1]).toFixed (schedulePrecision));
scheduleSelectedCity.attr ('lon', parseFloat (match [2]).toFixed (schedulePrecision));
var scheduleMap = scheduleMapList [form.find ('.scheduleMap').attr ('id')];
scheduleAddAllCityFromUl (scheduleMap, scheduleSelectedCity.closest ('ul'));
scheduleFocusCity ();
}
input.val (addr);
scheduleSelectedCity.find ('span.addresse').html (addr.replace (/~br~/gi, '<br/>'));
});
// default form validation for each text field
jQuery ('.scheduleMiscForm input').keypress (function (e) {
if (e.which != 13)
return;
jQuery (this).closest ('.scheduleTabForm').find ('input[type="submit"]').first ().trigger ('click');
});
// init maps
scheduleInitMaps ();
scheduleInitPOI ();
});
// ========================================