diff --git a/ipmd/static/ipmd/js/ipmdlib.js b/ipmd/static/ipmd/js/ipmdlib.js index f51a2bd3746fd548eec04f4e9168e1a6d25f7819..eb04428bb1e75c8cc0c98d2662b33818202c99c4 100644 --- a/ipmd/static/ipmd/js/ipmdlib.js +++ b/ipmd/static/ipmd/js/ipmdlib.js @@ -183,8 +183,8 @@ function getPragmaticWeatherParameterList(requestedParameters, availableParamete { completeList = completeList.concat(requestedParameters[i], fallbackParams[requestedParameters[i]]); } - console.info(completeList); - console.info(availableParameters); + //console.info(completeList); + //console.info(availableParameters); return completeList.filter(param => availableParameters.includes(param)); @@ -422,6 +422,10 @@ async function initDataSourceMap(containerId, geoJson, countryCodeList, featureC layers: [backgroundLayer], renderer: 'canvas' }); + + + + maps[containerId] = map; // Setting zoom and center for the map (need to do this after creating map. so that we can transform our // center to correct map projection) @@ -455,14 +459,17 @@ async function initDataSourceMap(containerId, geoJson, countryCodeList, featureC }); } + let featureOverlay = undefined; + if(drawnFeatures != undefined) { //console.info(drawnFeatures); // Create an empty layer - var featureOverlay = new ol.layer.Vector({ + featureOverlay = new ol.layer.Vector({ source: new ol.source.Vector({ features: features - }) + }), + style: styleUnselected }); // Add the stations or area featureOverlay.getSource().addFeatures(drawnFeatures); @@ -473,69 +480,102 @@ async function initDataSourceMap(containerId, geoJson, countryCodeList, featureC map.getView().fit(extent, map.getSize()); } + + + /* + * A little bit of this and that with regards to feature selection + * to make it work as we want + * - Highlight a selected station (but only one station, multiple select is not allowed) + * - If user clicks on multiple stations, zoom in to make it easy to pick the right one + */ + + let selectInteraction = new ol.interaction.Select({ + toggleCondition: ol.events.condition.never // Only one can be selected at a time + }); + map.addInteraction(selectInteraction); + selectInteraction.on("select", function(e){ + // If it's an area (id == undefined), don't mark it as selected + if(e.target.getFeatures().getLength() > 0 && e.target.getFeatures().item(0).getId() == undefined) + { + e.target.getFeatures().clear(); + } + else if(e.target.getFeatures().getLength() == 1) + { + let feature = e.target.getFeatures().item(0); + featureClickedCallback(feature.getId(), undefined); + } + }); + map.on('singleclick', function(evt) { var pixel = map.getEventPixel(evt.originalEvent); var coordinate = map.getEventCoordinate(evt.originalEvent); - displayFeatureDetails(map, pixel, coordinate, featureClickedCallback); + handleMapClicked(map, featureOverlay, pixel, coordinate, featureClickedCallback); }); } +const styleUnselected = new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(173, 173, 173, 0.5)' + }), + stroke: new ol.style.Stroke({ + color: '#000000', + width: 1 + }), + image: new ol.style.Circle({ + radius: 6, + fill: new ol.style.Fill({ + color: '#adadad' + }), + stroke: new ol.style.Stroke({ + color: '#000000', + width: 1 + }) + }) +}); + + /** * When a user clicks on the map, handles whatever was clicked (station, point in area, point outside any feature/area) * @param {ol.map} map + * @param {ol.layer} layer * @param {ol.Pixel} pixel * @param {ol.coordinate} coordinate * @param {Function} featureClickedCallback Callback function taking parameters ({String} id, {Array<Float>} coordinate) */ -function displayFeatureDetails(map, pixel, coordinate, featureClickedCallback) { +function handleMapClicked(map, layer, pixel, coordinate, featureClickedCallback) { var features = []; - map.forEachFeatureAtPixel(pixel, function(feature,layer){ + map.forEachFeatureAtPixel(pixel, function(feature){ features.push(feature); }); if (features.length == 1) { - // A station? Select station using features[i].getId() in callback - if(features[0].getId() !== undefined) - { - console.info("Station clicked: " + features[0].get("name") + ",id=" + features[0].getId()); - featureClickedCallback(features[0].getId(), getDecimalDegrees(map, coordinate)); - } - // An area? Return the coordinate of clicked point in callback - else + // Area + if(features[0].getId() === undefined) { featureClickedCallback(null, getDecimalDegrees(map, coordinate)); - console.info("Area clicked"); } + // Click on a station is handled in the select interaction (see initDataSourceMap) } - // Display popup,so that user can select their station + // The select interaction (see initDataSourceMap) highlights one and only one + // selected feature. If the clicked pixel has more than one feature, + // zoom in to let the user be able to separate the features else if(features.length > 1) { - console.info("Multiple stations clicked. TODO: Let user select from a popup") - for(var i in features) - { - // A station? Select station using features[i].getId() in callback - if(features[i].getId() !== undefined) - { - console.info("Station clicked: " + features[i].get("name") + ",id=" + features[i].getId()); - } - } + map.getView().setCenter(coordinate); + map.getView().setZoom(map.getView().getZoom() + 2); } - else - { - // No feature clicked. Do anything? - } }; /** * * @param {ol.Map} map * @param {Array<Float>} coordinate - * @returns the pixel coordinate from a map converted to WGS84 Decimal degrees + * @return {ol.Coordinate} the pixel coordinate from a map converted to WGS84 Decimal degrees */ function getDecimalDegrees(map, coordinate) { - return ol.coordinate.toStringXY(ol.proj.transform(coordinate, map.getView().getProjection().getCode(), 'EPSG:4326'),5); + return ol.proj.transform(coordinate, map.getView().getProjection().getCode(), 'EPSG:4326'); } async function getCountryBoundaries(countryCodeList) diff --git a/ipmd/templates/ipmd/saddlegallmidgeform.html b/ipmd/templates/ipmd/saddlegallmidgeform.html index c22bb02dac9924ac0aec75cda37edc43512c0cd9..aca2f7f97b45489c74d890d1d0656ab3b92f7926 100644 --- a/ipmd/templates/ipmd/saddlegallmidgeform.html +++ b/ipmd/templates/ipmd/saddlegallmidgeform.html @@ -67,9 +67,7 @@ </div> </fieldset> </div> - <div class="col-md-4"> - <div id="forecastDatasourceMap"></div> - </div> + <div class="col-md-4"></div> </div> <button class="btn btn-primary" type="button" onclick="submitData();">Submit</button> <div style="aspect-ratio: 2;"> @@ -208,16 +206,19 @@ function handleHistoricDatasourceMapClicked(id, coordinate) { - console.info("Map clicked, station=" + id +", coordinate=" + coordinate + ". TODO: select station and/or populate lat/lon fields"); + //console.info("Map clicked, station=" + id +", coordinate=" + coordinate + ". TODO: select station and/or populate lat/lon fields"); // id != null => station. Pull station coordinates from source list to avoid inacurracies in user's map click coordinate if(id !== null) { // Set the selected station setSelection(selectList, id); handleWeatherStationSelected(selectList); - // Call handleWeatherStationSelected() } // id == null => area. Use the provided coordinate + else + { + setLatLon(coordinate); + } } function setSelection(selectList, optionValue) @@ -258,8 +259,13 @@ let weatherStationId = selectList.options[selectList.selectedIndex].value; let stationCoordinate = getWeatherStationCoordinate(currentWeatherDatasource, weatherStationId); //console.info(stationCoordinate); - document.getElementById("longitude").value = stationCoordinate[0]; - document.getElementById("latitude").value = stationCoordinate[1]; + setLatLon(stationCoordinate); + } + + function setLatLon(coordinate) + { + document.getElementById("longitude").value = coordinate[0]; + document.getElementById("latitude").value = coordinate[1]; } async function submitData(){ @@ -364,7 +370,7 @@ inputData["weatherData"] = weatherData; - console.info(weatherData); + //console.info(weatherData); } // Ready to call server? //console.info(JSON.stringify(inputData));