Using Geotiff on Leafletjs - Get Value on Map Click - javascript

I can't get any value when I click on my map.
I just want to get the value of the pixel when map in onClick.
I tried using d3 and I make it to work, but using GeoRasterLayer load much faster on zoom that's why I am trying to make this work.
var map = L.map('map').setView([12.46876, 121.915039], 6);
var layer = "http://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png";
L.tileLayer(layer, {
attribution: "OSM & Carto",
subdomains: "abcd",
maxZoom: 19
}).addTo(map);
// tif file
var url_to_geotiff_file = "../src/rr.gpm1hr.20221026.233000.tif";
fetch(url_to_geotiff_file)
.then(response => response.arrayBuffer())
.then(arrayBuffer => {
parseGeoraster(arrayBuffer).then(georaster => {
const min = georaster.mins[0];
const max = georaster.maxs[0];
const range = georaster.ranges[0];
var scale = chroma.scale(['#FFFFCC' ,'#C7E9B4' ,'#7FCDBB' ,'#41B6C4' ,'#1D91C0' ,'#225EA8' ,'#0C2C84']);
var layer = new GeoRasterLayer({
georaster: georaster,
opacity: 0.7,
pixelValuesToColorFn: function(pixelValues) {
var pixelValue = pixelValues[0];
if (pixelValue === 0) return null;
var scaledPixelValue = (pixelValue - min) / range;
var color = scale(scaledPixelValue).hex();
return color;
},
resolution: 256
}).addTo(map);
map.on('click', function (e) {
if(e.pixelValue !== null){
let v = e.pixelValue;
let html = (`<span class="popupText">Value: ${v}</span>`);
let popup = L.popup()
.setLatLng(e.latlng)
.setContent(html)
.openOn(map);
}
});
});
});

Related

How to change the color of the marker in leaflet relative to the different values using vanilla js

I want to change the color of the markers on leaflet map relative to the different values.
I get lat & long from this API - example (lat is X, long is Y)
I get the data for checking values from this API - example - I want to check:
if level_11 and level_fw is between the values of ALERT_yewoll markers to be yellow color.
if level_11 and level_fw is between the values of ALERT_orange markers to be orange color.
if level_11 and level_fw is between the values of ALERT_red markers to be orange color.
For now I display all markers with the same color with this code:
//Create map
var map = L.map('map', {
minZoom: 7,
maxZoom: 9
}).setView([42.4258, 25.6345], 7);
//Map footer
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© НИМХ - АС и БД, Филиал Пловдив'
}).addTo(map);
const urlCoords = 'http://194.141.118.43:3010/stations';
// Create Asynchronous function to grab the data for filling dropdown
async function getData() {
try {
// We are using fetch to get the response
const responseCoords = await fetch(urlCoords);
const coordsStation = await responseCoords.json();
//console.log(coordsStation);
// Trigger the listData function and pass the result
listCoords(coordsStation);
} catch (error) {
console.log(error);
}
}
function listCoords(coordsStation) {
// Loop through each result and append the data.
coordsStation.floodguard_stations.rows.map(function (stationCoords, i) {
if (stationCoords.X != null && stationCoords.Y != null) {
var station = L.circle([stationCoords.X, stationCoords.Y], {
color: 'blue',
fillColor: '#566ad1',
fillOpacity: 0.5,
radius: 10000
}).addTo(map);
station.bindPopup(stationCoords.name_BG);
}
});
};
getData();
const urlCheckForWarnings = 'http://194.141.118.43:3010/alldata';
// Create Asynchronous function to grab the data for filling dropdown
async function getDataWarningsMikeFW() {
try {
// We are using fetch to get the response
const responseAllData = await fetch(urlCheckForWarnings);
const allDataModels = await responseAllData.json();
//console.log(coordsStation);
// Trigger the listData function and pass the result
listValues(allDataModels);
console.log(allDataModels);
} catch (error) {
console.log(error);
}
}
function listValues(allDataModels) {
// Loop through each result and append the data.
allDataModels.floodguard_alldata.rows.map(function (AllData, i) {
const formatDate = "YYYY-MM-DD HH:mm:ss";
if (AllData.level_11 >= 222.50 /*MikeAllData.ALERT_yewoll*/ && AllData.level_11 < 222.50 /*MikeAllData.ALERT_orange*/ && AllData.level_fw >= 222.50 /*MikeAllData.ALERT_yewoll*/ && AllData.level_fw < 222.50 /*MikeAllData.ALERT_orange*/) {
document.getElementById("mikeFWwarnings").innerHTML = "Предупреждение 1: Жълт код за: " + AllData.substring;
}
if (AllData.level_11 >= AllData.ALERT_orange && AllData.level_11 < AllData.ALERT_red && AllData.level_fw >= AllData.ALERT_orange && AllData.level_fw < AllData.ALERT_red) {
document.getElementById("mikeFWwarnings").innerHTML = "Предупреждение 2: Оранжев код за: " + AllData.substring;
}
if (AllData.level_11 >= AllData.ALERT_red && AllData.level_fw >= AllData.ALERT_red) {
document.getElementById("mikeFWwarnings").innerHTML = "Предупреждение 3: Червен код за: " + AllData.substring;
}
});
};
getDataWarningsMikeFW();
For Now I only check in the last function function listValues(allDataModels) If the values are in the range of values for alert_yewoll alert_orange and alert_red to display text in paragraph but I can't make the values check to color the markers ?
This code works for now and can be tried, but can I get an example of how I can change the colors of the markers according to the different values

`Uncaught Error: Map container is being reused by another instance` from second manual search

I am currently trying to make an IP address checker which checks user's ip on load and on the user's manual search using Leaflet and other apis like ipgeolocation and currencyconverer. Currently, the map loads perfectly on load and on the first manual search after load. But when I try to do the second manual IP search I get this -
Map.js:745 Uncaught Error: Map container is being reused by another instance
at i.remove (Map.js:745:10)
at HTMLButtonElement.mapOff (index.js:136:25)
and then the result shows up like the first search.
Why is it appearing and how do I solve it?
Github Repository Link - https://github.com/MustakAbsarKhan/ip-address-tracker
Code-
//loading map and it's features
mapload ();
function mapload (){
count++;
if(count===1){
//map initiation
var map = L.map('map').setView([latitude, longitude], 13);
}else if(count === 2){
var map = L.map('map').setView([latitude, longitude], 13);
count --;
}
//maptile setup
L.tileLayer('https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=Kiarb32YtKIgXk1i9lL1',{
tileSize: 512,
zoomOffset: -1,
minZoom: 1,
attribution: "\u003ca href=\"https://www.maptiler.com/copyright/\" target=\"_blank\"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e",
crossOrigin: true
}).addTo(map);
//map icon
var blackIcon = L.icon({
iconUrl: 'images/icon-location.svg',
iconSize: [30, 40]
});
//marker & popup on marker
L.marker([latitude, longitude],{icon: blackIcon}).addTo(map)
.bindPopup('Your IP Shows You Here')
.openPopup();
//popup on map click
var popup = L.popup();
function onMapClick(e) {
popup
.setLatLng(e.latlng)
.setContent("You clicked the map at " + e.latlng.toString())
.openOn(map);
}
map.on('click', onMapClick);
//leaflet-locatecontrol plugin
var lc = L.control.locate({
position: 'topleft',
tap: false,
strings: {
title: "Click here, to get your device's current location"
},
locateOptions: {
enableHighAccuracy: true
}
}).addTo(map);
count--;
function mapOff(){
map.off();
map.remove();
};
button.addEventListener('click',mapOff);
};
The issue is solved by separating the marker, making the code only reposition the marker if the map and layer are already defined.
The thing that did cause the problem was- The map and Its Layer Container were getting initialized over and over following the button click.
Hope someone in the future will find this solution useful.
The Code-
let count = 0;
ipgeolocationapiCALL(ipgeolocationAPI);
//if user clicks on the button
button.addEventListener("click", function () {
if (searchbox.value !== "") {
ipgeolocationAPI =
`https://api.ipgeolocation.io/ipgeo?${params}&ip=` + searchbox.value;
count++;
ipgeolocationapiCALL(ipgeolocationAPI);
};
});
//initialization of map on load cause the count value stays 0 at the beginning and when the search icon is pressed for the first time
function initializeMap(latitude, longitude) {
map = L.map("map").setView([latitude, longitude], 13);
L.tileLayer(
"https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=Kiarb32YtKIgXk1i9lL1",
{
tileSize: 512,
zoomOffset: -1,
minZoom: 1,
attribution:
'\u003ca href="https://www.maptiler.com/copyright/" target="_blank"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href="https://www.openstreetmap.org/copyright" target="_blank"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e',
crossOrigin: true,
}
).addTo(map);
var blackIcon = L.icon({
iconUrl: "images/icon-location.svg",
iconSize: [30, 40],
});
L.marker([latitude, longitude], { icon: blackIcon })
.addTo(map)
.bindPopup("Your IP Shows You Here")
.openPopup();
L.control
.locate({
position: "topleft",
tap: false,
strings: {
title: "Click here, to get your device's current location",
},
locateOptions: {
enableHighAccuracy: true,
},
})
.addTo(map);
}
function ipgeolocationapiCALL(api) {
//returns "ip": "103.145.74.149","continent_code": "AS","continent_name": "Asia","country_code2": "BD","country_code3": "BGD","country_name": "Bangladesh","country_capital": "Dhaka","state_prov": "Dhaka Division","district": "Savar Upazila","city": "Savar Union","zipcode": "","latitude": "23.86170","longitude": "90.25649","is_eu": false,"calling_code": "+880","country_tld": ".bd","languages": "bn-BD,en","country_flag": "https://ipgeolocation.io/static/flags/bd_64.png","geoname_id": "1200292","isp": "Master Net","connection_type": "","organization": "Master Net","currency": {"code": "BDT","name": "Bangladeshi Taka","symbol": "৳"},"time_zone": {"name": "Asia/Dhaka","offset": 6,"current_time": "2022-08-28 15:24:16.540+0600","current_time_unix": 1661678656.54,"is_dst": false,"dst_savings": 0
fetch(api)
.then((response) => response.json()) //collects data as json
.then((data) => {
//declaring contents of api as objects
const ip = data.ip; //103.145.74.149
const { city, country_name, isp, country_flag, latitude, longitude } =
data; //Dhaka, Bangladesh,Master Net
const { current_time, name } = data.time_zone; //"2022-08-27 23:25:49.527+0600";
const { code, symbol } = data.currency; //BDT,TAKA SYMBOL
let timezone = current_time.slice(current_time.length - 5); //+0600
let date = current_time.slice(0, current_time.search(" ")); // 2022-08-27
let time = current_time.slice(date.length + 1, date.length + 9); //23:01:28
let exactTimezone =
"UTC " +
timezone.slice(0, 3) +
":" +
timezone.slice(timezone.length - 2, timezone.length); //UTC +06:00
//assigning api values to html elements
ipAddress.textContent = ip;
cityData.textContent = city + ",";
countryData.textContent = country_name;
timezoneData.textContent = exactTimezone + ",";
timeData.textContent = time + ",";
dateData.textContent = date;
ispData.textContent = isp;
currencyData.textContent = code + ` (${symbol})`;
flagIcon.src = country_flag;
let currencyCODE = code; //assigining fetched value to this variable for being able to reassign value to following conditions
if (currencyCODE === "USD") {
currencyCODE = "EUR";
let xchangeRateAPI = `https://api.exchangerate.host/convert?from=USD&to=${currencyCODE}`;
xchangeRateAPICALL(xchangeRateAPI);
} else {
let xchangeRateAPI = `https://api.exchangerate.host/convert?from=USD&to=${currencyCODE}`;
xchangeRateAPICALL(xchangeRateAPI);
}
//calling exchange rate api. This one Converts USD to User's Currency and For users who lives in United States it would convert 1 USD to Euro.
function xchangeRateAPICALL(api) {
fetch(api)
.then((response) => response.json())
.then((data) => {
const { to } = data.query;
const { result } = data;
const convertedAmount = result.toFixed(2);
currencyconvertData.textContent =
"$ 1 = " + `${to} ${convertedAmount}`;
});
}
//default value of count is 0 which gets incremented in the previous if function(which checks if the input field has any value)
if (count === 0) {//initializing the map and the layout on load
initializeMap(latitude, longitude);
} else {//resetting the marker position as the map and layout is already initialized
var blackIcon = L.icon({
iconUrl: "images/icon-location.svg",
iconSize: [30, 40],
});
L.marker([latitude, longitude], { icon: blackIcon })
.addTo(map)
.bindPopup("Your IP Shows You Here")
.openPopup();
}
})
.catch((error) => {
console.log("Error is "+ error);
alert("Wrong IP. Please Try Again.");
searchbox.value = "";
});

Capture zoom out event in Cesium

I want to capture zoom out event as soon as user reduces the map size to an extent i have to change the Map image layer.
var viewer = new Cesium.Viewer("cesiumContainer");
var scene = viewer.scene;
var clock = viewer.clock;
var referenceFramePrimitive;
var camera = viewer.camera;
....
camera.changed.addEventListener(function()
{
var height = Cesium.Cartographic.fromCartesian(camera.position).height;
if(height<4251907)
{
var layers = viewer.imageryLayers;
var baseLayer = layers.get(0);
layers.remove(baseLayer);
layers.addImageryProvider(new Cesium.IonImageryProvider({ assetId: 3812, maximumLevel : 5 }));
}
console.log(height);
}.bind(camera));
Is there any way to achieve this.
Thanks
This is one of the very simple solutions.
const viewer = new Cesium.Viewer("cesiumContainer");
const camera = viewer.camera;
const scratchCartesian1 = new Cesium.Cartesian3();
const scratchCartesian2 = new Cesium.Cartesian3();
let startPos, endPos;
camera.moveStart.addEventListener(function () {
startPos = camera.positionWC.clone(scratchCartesian1);
});
camera.moveEnd.addEventListener(function () {
endPos = camera.positionWC.clone(scratchCartesian2);
const startHeight = Cesium.Cartographic.fromCartesian(startPos).height;
const endHeight = Cesium.Cartographic.fromCartesian(endPos).height;
if (startHeight > endHeight) {
console.log("zoom in");
} else {
console.log("zoom out");
}
});

Google Maps Polygons self intersecting detection

I'm trying to implement a polygon self intersection algorithm from Google Maps API V3 polygons.
The goal is just to detect if yes or no, a simple polygon drawn by the user is self crossing.
I have found this very interesting link, but it assumes that coordinates of the polygon's vertices are given on geoJSON format. However, this isn't my case ; I'm only able to retrieve polygons coordinates using polygon.getPath() into a polygoncomplete event.
This is how i retrieve the coordinates :
google.maps.event.addDomListener(drawingManager, 'polygoncomplete', function(polygon)
{
var polygonBounds = polygon.getPath();
var coordinates = [];
for(var i = 0 ; i < polygonBounds.length ; i++)
{
vertice = {
"Latitude" : polygonBounds.getAt(i).lat(),
"Longitude" : polygonBounds.getAt(i).lng()
}
coordinates.push(vertice );
}
}
How can I transform these coordinates, given by polygon.getpath() into geoJSON format ?
Is there any better way to detect if a Google Maps polygon is self-intersecting ? If so, could you please share some code sample and not just a mathematical explaination ?
PS : I've seen this link but without any code sample, I'm a little bit lost.
You don't need to convert them to GeoJSON to use the jsts library, you need to convert them from google.maps.LatLng objects to jsts.geom.Coordinates. Instead of using this:
var geoJSON2JTS = function(boundaries) {
var coordinates = [];
for (var i = 0; i < boundaries.length; i++) {
coordinates.push(new jsts.geom.Coordinate(
boundaries[i][1], boundaries[i][0]));
}
return coordinates;
};
Use this, which will convert coordinates in a google.maps.Polygon path to the JTS format:
var googleMaps2JTS = function(boundaries) {
var coordinates = [];
for (var i = 0; i < boundaries.getLength(); i++) {
coordinates.push(new jsts.geom.Coordinate(
boundaries.getAt(i).lat(), boundaries.getAt(i).lng()));
}
return coordinates;
};
then change "findSelfIntersects" like this:
/**
* findSelfIntersects
*
* Detect self-intersections in a polygon.
*
* #param {object} google.maps.Polygon path co-ordinates.
* #return {array} array of points of intersections.
*/
var findSelfIntersects = function(googlePolygonPath) {
var coordinates = googleMaps2JTS(googlePolygonPath);
var geometryFactory = new jsts.geom.GeometryFactory();
var shell = geometryFactory.createLinearRing(coordinates);
var jstsPolygon = geometryFactory.createPolygon(shell);
// if the geometry is aleady a simple linear ring, do not
// try to find self intersection points.
var validator = new jsts.operation.IsSimpleOp(jstsPolygon);
if (validator.isSimpleLinearGeometry(jstsPolygon)) {
return;
}
var res = [];
var graph = new jsts.geomgraph.GeometryGraph(0, jstsPolygon);
var cat = new jsts.operation.valid.ConsistentAreaTester(graph);
var r = cat.isNodeConsistentArea();
if (!r) {
var pt = cat.getInvalidPoint();
res.push([pt.x, pt.y]);
}
return res;
};
proof of concept fiddle (credit to HoffZ)
code snippet:
var mapOptions = {
zoom: 16,
center: new google.maps.LatLng(62.1482, 6.0696)
};
var drawingManager = new google.maps.drawing.DrawingManager({
drawingControl: false,
polygonOptions: {
editable: true
}
});
var googleMaps2JTS = function(boundaries) {
var coordinates = [];
for (var i = 0; i < boundaries.getLength(); i++) {
coordinates.push(new jsts.geom.Coordinate(
boundaries.getAt(i).lat(), boundaries.getAt(i).lng()));
}
coordinates.push(coordinates[0]);
console.log(coordinates);
return coordinates;
};
/**
* findSelfIntersects
*
* Detect self-intersections in a polygon.
*
* #param {object} google.maps.Polygon path co-ordinates.
* #return {array} array of points of intersections.
*/
var findSelfIntersects = function(googlePolygonPath) {
var coordinates = googleMaps2JTS(googlePolygonPath);
var geometryFactory = new jsts.geom.GeometryFactory();
var shell = geometryFactory.createLinearRing(coordinates);
var jstsPolygon = geometryFactory.createPolygon(shell);
// if the geometry is aleady a simple linear ring, do not
// try to find self intersection points.
var validator = new jsts.operation.IsSimpleOp(jstsPolygon);
if (validator.isSimpleLinearGeometry(jstsPolygon)) {
return;
}
var res = [];
var graph = new jsts.geomgraph.GeometryGraph(0, jstsPolygon);
var cat = new jsts.operation.valid.ConsistentAreaTester(graph);
var r = cat.isNodeConsistentArea();
if (!r) {
var pt = cat.getInvalidPoint();
res.push([pt.x, pt.y]);
}
return res;
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
drawingManager.setDrawingMode(google.maps.drawing.OverlayType.POLYGON);
drawingManager.setMap(map);
google.maps.event.addListener(drawingManager, 'polygoncomplete', function(polygon) {
//var polyPath = event.overlay.getPath();
var intersects = findSelfIntersects(polygon.getPath());
console.log(intersects);
if (intersects && intersects.length) {
alert('Polygon intersects itself');
} else {
alert('Polygon does not intersect itself');
}
});
#map {
width: 500px;
height: 400px;
}
<script src="https://maps.google.com/maps/api/js?libraries=drawing&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<script src="https://cdn.rawgit.com/bjornharrtell/jsts/gh-pages/1.4.0/jsts.min.js"></script>
<p>
Draw a polygon on the map
</p>
<div id="map">
</div>

OL3: GetFeature from Layers by Coordinate

I want to get the Feature of a Layer by coordinate.
Furthermore I want to open this feature in a popup, which I have solved so far by an onclick event. But I want to realize by giving the coordinates of a feature and opening the popup of the featue.
I have a layer with the map and a layer with the features:
if (trackMap != null) {
for (var i = 0; i < trackMap.length; i++) {
var trackInfo = trackMap[i];
lat = parseFloat(trackInfo.lat);
lon = parseFloat(trackInfo.lon);
var layergpx = new ol.layer.Vector({
source: new ol.source.Vector({
parser: new ol.parser.GPX(),
url: '${contextRoot}/gps/gpx2' + trackInfo.url
})
});
layers.push(layergpx);
}
}
I want to get the feature of this layer in another Javascript function.
How I open a pop up by clicking on the map:
/**
* The Click Event to show the data
*/
var element = document.getElementById('popup');
var popup = new ol.Overlay({
element: element,
positioning: ol.OverlayPositioning.BOTTOM_CENTER,
stopEvent: false
});
map.addOverlay(popup);
map.on('singleclick', function(evt) {
map.getFeatures({
pixel: evt.getPixel(),
layers: vectorLayers,
success: function(layerFeatures) {
var feature = layerFeatures[0][0];
if (feature) {
var geometry = feature.getGeometry();
var coord = geometry.getCoordinates();
popup.setPosition(coord);
$(element).popover({
'placement': 'top',
'html': true,
'content': feature.get('desc')
});
$(element).popover('show');
} else {
$(element).popover('destroy');
}
}
});
});
But I want this feature not to be opened by clicking on it on the map, but by entering a coordinate in a textfield and the map opens this pop up, like in the onclick event.
Take a look at this example to see if it helps you:
http://openlayers.org/en/latest/examples/kml.html
var displayFeatureInfo = function(pixel) {
map.getFeatures({
pixel: pixel,
layers: [vector],
success: function(featuresByLayer) {
var features = featuresByLayer[0];
var info = [];
for (var i = 0, ii = features.length; i < ii; ++i) {
info.push(features[i].get('name'));
}
document.getElementById('info').innerHTML = info.join(', ') || '&nbsp';
}
});
map.getFeatures() has this success callback where it delivers the features of the layers specified in layers: [vector]. Customize it at will to get what you need.
=== Update ===
In the OpenLayers 3's Map object you have a function: getPixelFromCoordinate
/**
* #param {ol.Coordinate} coordinate Coordinate.
* #return {ol.Pixel} Pixel.
*/
ol.Map.prototype.getPixelFromCoordinate = function(coordinate) {
var frameState = this.frameState_;
if (goog.isNull(frameState)) {
return null;
} else {
var vec2 = coordinate.slice(0, 2);
return ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, vec2, vec2);
}
};

Categories

Resources