I have 2 main function on my project, 1 to display information, vectors,layers, etc when page loads and another one to display information depending what the user want to see.
I am calling geoserver to display geotiff as imageWMS , also i am displaying band values from this geotiff on geoserver using this function showBand:
eventRaster = (f) => {
rasterWMS = new ol.source.ImageWMS({
url: 'https://url/geoserver/name/wms',
params: {
'LAYERS': 'name:' + f
},
ratio: 1,
serverType: 'geoserver'
})
return rasterWMS;
}
showBand = (map, vista, eventRaster) => {
map.on('singleclick', function (evt) {
/* document.querySelector('featureInfo > tr').classList.add("test") */
const viewResolution = /** #type {number} */ (vista.getResolution());
const url = eventRaster.getFeatureInfoUrl(
evt.coordinate,
viewResolution,
'EPSG:3857',
{ 'INFO_FORMAT': 'text/html' }
);
if (url) {
fetch(url)
.then((response) => response.text())
.then((html) => {
document.getElementById('showBand').innerHTML = html;
const pga = document.querySelector(".featureInfo tbody tr:nth-child(2) td:nth-child(2)").textContent;
const floatPga = parseFloat(pga).toFixed(2);
if (floatPga < 0) {
document.getElementById('showBand').innerHTML = "Da click en la una zona vĂ¡lida";
} else {
document.getElementById('showBand').innerHTML = floatPga + " gal";
}
});
}
});
map.on('pointermove', function (evt) {
if (evt.dragging) {
return;
}
const pixel = map.getEventPixel(evt.originalEvent);
const hit = map.forEachLayerAtPixel(pixel, function () {
return true;
});
/* map.getTargetElement().style.cursor = hit ? 'pointer' : ''; */
});
}
So i have this on my functions:
firstLoad(){
const f = sometiffname;
lastTiffRaster = new ol.layer.Image({
title: 'PGA(gal)',
source: eventRaster(f),
});
map.addLayer(lastTiffRaster);
}
selected(){
const f = sometiffname;
map.removeLayer(lastTiffRaster);
map.removeLayer(eventTiff);
rasterWMS.updateParams({
'LAYERS': 'name:'+f,
});
evetTiff = new ol.layer.Image({
title: 'PGA(gal)',
source: eventRaster(f),
});
map.addLayer(eventTiff);
}
There is not problem when page loads for first time and click the first event i want to see because params update perfectly, and i can see band values without problems, but when i try to call another event (the second one), geotiff changes, but params does not update. i print on console f to see whats the value and it changes per event but i dont know why updateParams doesnt work on this situation.
yellow marker is f
I had to create a new imagewms for selected() then update imagewms from firstload()
selected(){
const f = sometiffname;
const newRasterWMS = new ol.source.ImageWMS({
url: 'https://url.pe/geoserver/somename/wms',
params: {
'LAYERS': 'somename:' + f
},
ratio: 1,
serverType: 'geoserver'
});
rasterWMS.updateParams({
'LAYERS': 'somename:'+f,
});
eventTiff = new ol.layer.Image({
title: 'PGA(gal)',
source: newRasterWMS
});
map.addLayer(lastTiffRaster);
}
Related
I am trying to create a cluster map with multiple locations in the same area. Now, I have this pop-up with data which is coming from my API. I have a click event that toggles the pop-up on click for each location. But the problem is even when I specified the click unique ID to toggle it still opens all the pop-ups. Also, the zoom is not working for the clusters count circles.
This is my code:
import mapboxgl from 'mapbox-gl';
import MapboxLanguage from '#mapbox/mapbox-gl-language';
import apiFetch from '#wordpress/api-fetch';
(() => {
const mapContainer = document.querySelector('[data-gewoon-wonen]');
if (!mapContainer) {
return;
}
mapboxgl.accessToken = process.env.MAP_TOKEN_KEY;
const filterGroup = document.getElementById('map-filter');
const resetButton = filterGroup.querySelector('.hidden');
const center = [4.387733, 51.862419];
const locations = {
type: 'FeatureCollection',
features: []
};
apiFetch({ path: '/wp-json/wp/v2/map?_embed' }).then((maps) => {
maps.forEach((item) => {
const {
id,
title: { rendered: title },
_embedded,
acf
} = item;
const image =
_embedded && _embedded['wp:featuredmedia'][0]?.source_url;
const {
map_location_subtitle: subtitle,
map_location_delivery: delivery,
map_location_project: project,
map_location_content: description,
map_location_coordinates_lat: lat,
map_location_coordinates_lng: lng,
map_location_status: status,
map_location_website: website
} = acf;
const getStatus = (currentStatus) => {
let statusObj = {
bouwfase: 'marker-gray',
planfase: 'marker-bright-pink',
opgeleverd: 'marker-bright-blue',
default: ''
};
let icon = statusObj[currentStatus] || statusObj['default'];
return icon;
};
const object = {
type: 'Feature',
properties: {
id,
status,
image,
icon: getStatus(status),
title,
subtitle,
project,
website,
delivery,
description
},
geometry: {
type: 'Point',
coordinates: [lng, lat]
}
};
locations.features.push(object);
});
});
const map = new mapboxgl.Map({
container: mapContainer,
style: 'mapbox://styles/.../clcz9eocm000p14o3vh42tqfj',
center,
zoom: 10,
minZoom: 10,
maxZoom: 18,
attributionControl: false,
cooperativeGestures: true
});
map.addControl(
new MapboxLanguage({
defaultLanguage: 'mul'
})
);
const resetActiveItems = () => {
document
.querySelectorAll('.active')
.forEach((e) => e.classList.remove('active'));
};
const closePopUps = () => {
const popups = document.getElementsByClassName('mapboxgl-popup');
if (popups.length) {
popups[0].remove();
}
};
map.on('load', () => {
map.addSource('locations', {
type: 'geojson',
data: locations,
cluster: true,
clusterMaxZoom: 14, // Max zoom to cluster points on
clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)s
});
locations.features.forEach((location) => {
const {
description,
delivery,
title,
subtitle,
project,
status,
image,
website,
id
} = location.properties;
const { coordinates } = location.geometry;
const layerID = `status-${status}-${id}`;
// Add a layer for this symbol type if it hasn't been added already.
if (!map.getLayer(layerID)) {
map.addLayer({
id: layerID,
type: 'symbol',
source: 'locations',
layout: {
'icon-image': ['get', 'icon'],
'icon-size': 0.9,
'icon-allow-overlap': true
},
// filter: ['==', 'id', id]
filter: ['!', ['has', 'point_count']]
});
map.addLayer({
id: `clusters-${id}`,
type: 'circle',
source: 'locations',
filter: ['has', 'point_count'],
paint: {
// Use step expressions (https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-step)
// with three steps to implement three types of circles:
// * Blue, 20px circles when point count is less than 100
// * Yellow, 30px circles when point count is between 100 and 750
// * Pink, 40px circles when point count is greater than or equal to 750
'circle-color': [
'step',
['get', 'point_count'],
'#51bbd6',
100,
'#f1f075',
750,
'#f28cb1'
],
'circle-radius': [
'step',
['get', 'point_count'],
20,
100,
30,
750,
40
]
}
});
map.addLayer({
id: `cluster-count-${id}`,
type: 'symbol',
source: 'locations',
filter: ['has', 'point_count'],
layout: {
'text-field': ['get', 'point_count_abbreviated'],
'text-font': [
'DIN Offc Pro Medium',
'Arial Unicode MS Bold'
],
'text-size': 12
}
});
}
const hasImage = image
? `<img src=${image} class="map__image" />`
: '';
const statusClass = image ? 'map__status--overlay' : '';
const popup = new mapboxgl.Popup({
offset: 25,
maxWidth: null,
className: image ? 'map__content--image' : ''
});
const content = `
${hasImage}
<span class="map__status map__status--${status} ${statusClass}">${status}</span>
<h4 class="map__title">${title}</h4>
<p class="map__subtitle">${subtitle}</p>
<p class="map__subtitle">${
delivery ? `Oplevering ${delivery}` : ''
}</p>
<p class="map__project">${project}</p>
<p class="map__info">${description}</p>
Meer informatie
`;
map.on('click', layerID, (e) => {
// Copy coordinates array.
const coordinateSlice = coordinates.slice();
resetButton.classList.remove('hidden');
// Ensure that if the map is zoomed out such that multiple
// copies of the feature are visible, the popup appears
// over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinateSlice[0]) > 180) {
coordinateSlice[0] +=
e.lngLat.lng > coordinateSlice[0] ? 360 : -360;
}
popup.setLngLat(coordinates).setHTML(content).addTo(map);
});
// Change the cursor to a pointer when the mouse is over the places layer.
map.on('mouseenter', layerID, () => {
map.getCanvas().style.cursor = 'pointer';
});
// Change it back to a pointer when it leaves.
map.on('mouseleave', layerID, () => {
map.getCanvas().style.cursor = '';
});
});
const statusTypes = locations.features.map(
(feature) => feature.properties.status
);
const uniqueStatusTypes = Array.from(new Set(statusTypes));
const newGeoJSON = { ...locations };
resetButton.addEventListener('click', () => {
newGeoJSON.features = [...locations.features];
map.getSource('locations').setData(newGeoJSON);
map.setZoom(10).setCenter(center);
resetButton.classList.add('hidden');
resetActiveItems();
closePopUps();
});
const sortedStatusTypes = [
uniqueStatusTypes[0],
uniqueStatusTypes[2],
uniqueStatusTypes[1]
].filter((status) => status !== undefined && status !== null);
sortedStatusTypes.forEach((statusType) => {
const input = document.createElement('input');
input.value = statusType;
input.name = statusType;
input.type = 'button';
input.className = `status--${statusType}`;
input.innerText = statusType;
filterGroup.appendChild(input);
input.onclick = () => {
const statusType = input.value;
resetActiveItems();
closePopUps();
if (statusType) {
input.classList.add('active');
resetButton.classList.remove('hidden');
newGeoJSON.features = locations.features.filter(
(feature) => feature.properties.status === statusType
);
}
map.getSource('locations').setData(newGeoJSON);
};
});
// disable map rotation using right click + drag
map.dragRotate.disable();
// disable map rotation using touch rotation gesture
map.touchZoomRotate.disableRotation();
// Add zoom and rotation controls to the map.
const nav = new mapboxgl.NavigationControl({
showCompass: false
});
const fullscreen = new mapboxgl.FullscreenControl();
map.addControl(fullscreen, 'top-right');
map.addControl(nav, 'bottom-right');
});
})();
I need to see the pixel value from a single visible WMS. In my project I've this two WMS:
/// WMS sources and layers
var wms_path = 'https://gis.massimilianomoraca.it/geoserver/MassimilianoMoraca/wms';
var sourceNDVI_20150807 = new ol.source.TileWMS({
url: wms_path,
params: {
'LAYERS': 'NDVI_Campania_20150807',
},
});
var titleNDVI_20150807 = 'NDVI_Campania_20150807';
var layerNDVI_20150807 = new ol.layer.Tile({
title: titleNDVI_20150807,
source: sourceNDVI_20150807,
visible: false
});
var sourceNDVI_20160712 = new ol.source.TileWMS({
url: wms_path,
params: {
'LAYERS': 'NDVI_Campania_20160712',
},
});
var layerNDVI_20160712 = new ol.layer.Tile({
title: 'NDVI_Campania_20160712',
source: sourceNDVI_20160712,
visible: false
});
I'm be able to see on the map this datas. I've created the function below whit the aim to active and deactive the single layer.
<button type="button" class="btn btn-primary"
onclick="NDVI_Campania_20150807()">NDVI_Campania_20150807</button>
<button type="button" class="btn btn-success"
onclick="NDVI_Campania_20160712()">NDVI_Campania_20160712</button>
function NDVI_Campania_20150807() {
console.log('NDVI_Campania_20150807');
map.removeLayer(layerNDVI_20160712);
map.addLayer(layerNDVI_20150807);
layerNDVI_20150807.setVisible(true);
/// Click on pixel
map.on('singleclick', function(evt) {
var coordinate = evt.coordinate;
var resolution = view.getResolution();
var projection = 'EPSG:3857';
var params = {
'INFO_FORMAT': 'application/json',
};
var url_20150807 = sourceNDVI_20150807.getFeatureInfoUrl(
coordinate, resolution, projection, params
);
fetch(url_20150807)
.then(function (response) {
return response.text(); })
.then(function (data) {
json = JSON.parse(data).features[0];
ndvi_20150807 = json.properties.GRAY_INDEX;
date_20150807 = '7 agosto 2015';
index_20150807 = [1,date_20150807,ndvi_20150807]
}).catch((error) => {
console.warn(error)
});
});
};
function NDVI_Campania_20160712() {
console.log('NDVI_Campania_20160712');
map.removeLayer(layerNDVI_20150807);
map.addLayer(layerNDVI_20160712);
layerNDVI_20160712.setVisible(true);
layerNDVI_20150807.setVisible(false);
/// Funzione click pixel
map.on('singleclick', function(evt) {
var coordinate = evt.coordinate;
var resolution = view.getResolution();
var projection = 'EPSG:3857';
var params = {
'INFO_FORMAT': 'application/json',
};
var url_20160712 = sourceNDVI_20160712.getFeatureInfoUrl(
coordinate, resolution, projection, params
);
fetch(url_20160712)
.then(function (response) {
return response.text(); })
.then(function (data) {
var json = JSON.parse(data).features[0];
ndvi_20160712 = json.properties.GRAY_INDEX;
date_20160712 = '12 luglio 2016';
index_20160712 = [2,date_20160712,ndvi_20160712]
console.log(index_20160712);
}).catch((error) => {
console.warn(error)
});
});
};
I can active and deactive the layers but if I click on the pixel I see the datas from both layers. How I can see the pixel value from the active layer?
In your button click handlers only change the layers
function NDVI_Campania_20150807() {
console.log('NDVI_Campania_20150807');
map.removeLayer(layerNDVI_20160712);
map.addLayer(layerNDVI_20150807);
layerNDVI_20150807.setVisible(true);
layerNDVI_20160712.setVisible(false);
};
function NDVI_Campania_20160712() {
console.log('NDVI_Campania_20160712');
map.removeLayer(layerNDVI_20150807);
map.addLayer(layerNDVI_20160712);
layerNDVI_20160712.setVisible(true);
layerNDVI_20150807.setVisible(false);
};
and set a single map click listener which queries whichever layer is visible
map.on('singleclick', function(evt) {
var coordinate = evt.coordinate;
var resolution = view.getResolution();
var projection = 'EPSG:3857';
var params = {
'INFO_FORMAT': 'application/json',
};
if (layerNDVI_20150807.getVisible()) {
var url_20150807 = sourceNDVI_20150807.getFeatureInfoUrl(
coordinate, resolution, projection, params
);
fetch(url_20150807)
.then(function (response) {
return response.text(); })
.then(function (data) {
json = JSON.parse(data).features[0];
ndvi_20150807 = json.properties.GRAY_INDEX;
date_20150807 = '7 agosto 2015';
index_20150807 = [1,date_20150807,ndvi_20150807]
}).catch((error) => {
console.warn(error)
});
} else if (layerNDVI_20160712.getVisible()) {
var url_20160712 = sourceNDVI_20160712.getFeatureInfoUrl(
coordinate, resolution, projection, params
);
fetch(url_20160712)
.then(function (response) {
return response.text(); })
.then(function (data) {
var json = JSON.parse(data).features[0];
ndvi_20160712 = json.properties.GRAY_INDEX;
date_20160712 = '12 luglio 2016';
index_20160712 = [2,date_20160712,ndvi_20160712]
console.log(index_20160712);
}).catch((error) => {
console.warn(error)
});
}
});
i am using react quill editor for my project and using my backend server to image upload but i need to access props inside the image handler of react quill and i am unable to do so as not able to access this object inside image handler.
here is my editor code.
<ReactQuill
ref={(el) => (this.quillRef = el)}
onChange={this.handleChange}
placeholder={"share your thoughts"}
modules={{
toolbar: {
container: [
[{ header: "1" }, { header: [2, 3, 4, 5, 6] }, { font: [] }],
[{ size: ["small", false, "large", "huge"] }],
["bold", "italic", "underline", "strike", "blockquote"],
[{ list: "ordered" }, { list: "bullet" }],
["link", "image", "video"],
["clean"],
["code-block"],
[{ color: [] }, { background: [] }], // dropdown with defaults from theme
[{ align: [] }],
],
handlers: {
image: this.imageHandler,
},
},
}}
/>;
function imageHandler() {
let self = this;
let image;
let image_extension;
const Cryptr = require("cryptr");
const cryptr = new Cryptr(key);
const users = localStorage.getItem("users")
? JSON.parse(cryptr.decrypt(localStorage.getItem("users")))
: {};
// console.log(users[users.lastLoginId])
let loggedinUser = users[users.lastLoginId];
const input = document.createElement("input");
input.setAttribute("type", "file");
input.setAttribute("accept", "image/*");
input.setAttribute("class", "Editor-mage");
input.click();
input.onchange = async () => {
//debugger
const file = input.files[0];
var ValidImageTypes = [
"image/gif",
"image/jpeg",
"image/png",
"image/jpg",
"image/GIF",
"image/JPEG",
"image/PNG",
"image/JPG",
];
let file_type = file.type;
let filename = file.name;
let extension = filename.split(".").pop();
if (ValidImageTypes.indexOf(file_type) >= 0) {
if (true) {
var fileToLoad = file;
loadImage(
fileToLoad,
(canvas) => {
if (canvas) {
// this.setState({
image = canvas.toDataURL();
image_extension = extension;
//});
const res = new Promise(function (resolve, reject) {
axios({
method: "post",
url: API_URL + "api/v1/postblogimage",
headers: {
"x-access-handler": loggedinUser.token,
},
data: {
image: image,
image_extension: image_extension,
userid: loggedinUser.userid,
},
})
//axios.post(API_URL + 'api/v1/postblogimage', formData, config)
.then((response) => {
//debugger
if (
response.data.error == "false" ||
response.data.error == false
) {
if (
response.data.status == 200 &&
response.data.message == "Image uploaded successfully"
) {
//debugger
const range = self.quill.getSelection(true);
// Insert temporary loading placeholder image
// this.quill.insertEmbed(range.index, 'image', `${window.location.origin}/images/loaders/placeholder.gif`);
// Move cursor to right side of image (easier to continue typing)
self.quill.setSelection(range.index + 1);
// Remove placeholder image
self.quill.deleteText(range.index, 1);
// Insert uploaded image
let url = response.data.data[0].imageURL;
self.quill.insertEmbed(range.index, "image", url);
self.quill.pasteHTML(
range.index,
<img
src={url}
class="blog-image-content"
alt="Responsive image"
/>
);
}
}
// }
})
.catch((error) => {
// reject(Error("It broke"));
});
});
}
},
{ orientation: true }
);
} else {
// this.setState({
// image_warning:'File size larger than maximum allowed limit',
image = "";
image_extension = "";
// })
this.fileInput.value = "";
}
} else {
}
};
}
can someone please help me out with this one as i am stuck for long on this.
any help and suggestion will be greatly appreciated.
I read the documentation of Quilljs.
Handler functions will be bound to the toolbar (so using this will refer to the toolbar instance) and passed the value attribute of the input if the corresponding format is inactive, and false otherwise. Adding a custom handler will overwrite the default toolbar and theme behavior.
and found out the imageHandler will be called in the context of the toolbar, so this.props will not work as intended when it is called.
so to achieve the accesss to props , you can do something like this:
handlers: {
image: (val) => this.imageHandler({ val, componentProps: this.props });
}
In the imageHandler you can access it like this:
function imageHandler({ val, componentProps }) {
// componentProps has all your propss, try to print it and see
// rest of your code, instead of this.props.something take componentProps.something
}
Let me know if it helps. Thanks
I think you can use higher order function.
image: this.imageHandler(props)
...
function imageHandler(props) {
return function() {
let self = this;
let image;
...
}
}
I'm using VueJS 2 and Firestore for this project.
I have an infinite loading method, where I need the next item to load, when the user hits the bottom of the page on scroll.
Everything is in the same method called getStraps()
The idea is to have a first set of items to load, and when the user hits the bottom, then it should load the next batch of items.
Main problem: The first two items are loading as usual, and then another one is loading. But then when I scroll another time, the 4th item repeats to be the same as the 3rd as so on. The variable "lastVisible" doesn't seem to update, so it won't load the following items with "startAfter"
Video: http://recordit.co/TwqEb4SeWe
getStraps() {
var strapper = db.collection("straps");
var first = strapper.limit(2);
return first.get().then(documentSnapshots => {
var lastVisible =
documentSnapshots.docs[documentSnapshots.docs.length - 1];
console.log("first last visible", lastVisible);
const straps = [];
documentSnapshots.forEach(doc => {
const data = {
id: doc.id,
title: doc.data().title,
price: doc.data().price,
skin: doc.data().skin,
type: doc.data().type,
imgs: doc.data().imgs[0].url,
colors: doc.data().colors,
desc: doc.data().desc,
date: doc
.data()
.date.toString()
.slice(0, 15)
};
straps.push(data);
});
this.straps = straps;
var next = strapper.startAfter(lastVisible).limit(1);
window.onscroll = () => {
let bottomOfWindow =
document.documentElement.scrollTop + window.innerHeight ===
document.documentElement.offsetHeight;
if (bottomOfWindow) {
this.fetchingData = true;
console.log("fetch", this.fetchingData);
return next.get().then(documentSnapshots => {
var lastVisible =
documentSnapshots.docs[documentSnapshots.docs.length - 1];
console.log("last last", lastVisible);
if (documentSnapshots.empty) {
this.fetchingData = false;
this.noMoreStraps = true;
} else {
documentSnapshots.forEach(doc => {
const straps = this.straps;
const data = {
id: doc.id,
title: doc.data().title,
price: doc.data().price,
skin: doc.data().skin,
type: doc.data().type,
imgs: doc.data().imgs[0].url,
colors: doc.data().colors,
desc: doc.data().desc,
date: doc
.data()
.date.toString()
.slice(0, 15)
};
console.log("more data", data);
straps.push(data);
this.fetchingData = false;
});
this.straps = straps;
}
});
}
};
});
},
I am using mirage for creating fake data.
scenario/default.js
export default function(server) {
server.createList('product', 48);
server.loadFixtures();
}
Above I am creating 48 products and from controller I am calling
this.store.query('product', {
filter: {
limit: 10,
offset: 0
}
}).then((result) => {
console.log(result);
});
and in mirage/config.js
this.get('/products', function(db) {
let products = db.products;
return {
data: products.map(attrs => ({
type: 'product',
id: attrs.id,
attributes: attrs
}))
};
});
now my question is, how to load 10 products per page? I am sending in filter 10 as page size and offset means page number.
what changes should be done to config.js to load only limited products?
In your handler in mirage/config.js:
this.get('/products', function(db) {
let images = db.images;
return {
data: images.map(attrs => ({
type: 'product',
id: attrs.id,
attributes: attrs
}))
};
});
You are able to access the request object like so:
this.get('/products', function(db, request) {
let images = db.images;
//use request to limit images here
return {
data: images.map(attrs => ({
type: 'product',
id: attrs.id,
attributes: attrs
}))
};
});
Have a look at this twiddle for a full example.
Where the this twiddle has the following:
this.get('tasks',function(schema, request){
let qp = request.queryParams
let page = parseInt(qp.page)
let limit = parseInt(qp.limit)
let start = page * limit
let end = start + limit
let filtered = tasks.slice(start,end)
return {
data: filtered
}
})
You'll just adapt it for your use like this:
this.get('products',function(db, request){
let qp = request.queryParams
let offset = parseInt(qp.offset)
let limit = parseInt(qp.limit)
let start = offset * limit
let end = start + limit
let images = db.images.slice(start,end)
return {
data: images.map(attrs => ({
type: 'product',
id: attrs.id,
attributes: attrs
}))
}
})
An example with todos, you can adapt it to your own use case.
// Fetch all todos
this.get("/todos", (schema, request) => {
const {queryParams: { pageOffset, pageSize }} = request
const todos = schema.db.todos;
if (Number(pageSize)) {
const start = Number(pageSize) * Number(pageOffset)
const end = start + Number(pageSize)
const page = todos.slice(start, end)
return {
items: page,
nextPage: todos.length > end ? Number(pageOffset) + 1 : undefined,
}
}
return todos
});