I'm trying to build the barcode scanner using the html5-qrcode npm package in react js, everything working fine except QR shaded region. I added the qrbox in the configuration but not getting the QR shaded region. The qrbox width and height are not taken. I tried multiple ways not getting the desired result. Thanks in advance.
Here is my component:
import { Html5QrcodeScanner, Html5Qrcode } from "html5-qrcode";
import React from 'react';
const qrcodeRegionId = "html5qr-code-full-region";
class Html5QrcodePlugin extends React.Component {
render() {
return <div id={qrcodeRegionId} />;
}
componentWillUnmount() {
this.html5QrcodeScanner.clear().catch(error => {
console.error("Failed to clear html5QrcodeScanner. ", error);
});
}
componentDidMount() {
function createConfig(props) {
var config = {};
if (props.fps) {
config.fps = props.fps;
}
config.qrbox = { width: 250, height: 250 };
if (props.aspectRatio) {
config.aspectRatio = props.aspectRatio;
}
if (props.disableFlip !== undefined) {
config.disableFlip = props.disableFlip;
}
return config;
}
var config = createConfig(this.props);
var verbose = this.props.verbose === true;
if (!(this.props.qrCodeSuccessCallback )) {
throw "qrCodeSuccessCallback is required callback.";
}
this.html5QrcodeScanner = new Html5QrcodeScanner(
qrcodeRegionId, { facingMode: { exact: "environment"} }, config, verbose);
this.html5QrcodeScanner.render(
this.props.qrCodeSuccessCallback,
this.props.qrCodeErrorCallback);
}
};
export default Html5QrcodePlugin;
Related
Basically I'm upgrading React Navigation from version 4 to 6. I have an area where navigation.dangerouslyGetParent().state; was used to get the state of the previous route.
I know that they switched out "dangerouslyGetParent" for "getParent" and "navigation.state" out for "route.state".
But what about this case? Thanks!
the block of code in question...
const { navigation } = this.props;
const { navBack } = this.state;
this.hideToast();
if (navBack) {
const parentRoute = navigation.dangerouslyGetParent().state;
const backRoute = getBackRouteName(
parentRoute,
parentRoute.index - 1
);
if (backRoute === null) {
navigation.navigate(navBack);
} else {
const replaceAction = StackActions.replace({
key: backRoute.key,
routeName: navBack,
params: {
navBack,
},
});
navigation.dispatch(replaceAction);
navigation.goBack();
}
} else {
navigation.goBack();
}
return true;
};
I have a component that I want to show a graph with multiple line series representing price changes over the last 24 hours. I have an endpoint that sends this data and I use the code below to show it.
One of the issues comes from errors seeming to come from the library itself meaning the graph will not even show up. Errors from the console when I load the page.
Other times, the page will load for a second and then go white and drain enough CPU to cause a crash.
The few times that the graph actually shows up on screen, it does not show any lines until the lines 81-85 are uncommented which it then shows the lines but does not zoom in on them leaving a mess on the screen.
Any help would be much appreciated.
/* eslint-disable new-cap */
/* eslint-disable #typescript-eslint/no-unused-vars */
/* eslint-disable no-magic-numbers */
import React, { useEffect, useState } from "react";
import { LegendBoxBuilders, lightningChart, Themes } from "#arction/lcjs";
import "./TopCurrencyGraph.css";
import axios from "axios";
export interface data {
data: dataPoint[];
}
export interface dataPoint {
currency: string;
percentage: number;
timestamp: string;
}
interface graphPoint {
x: number;
y: number;
}
const TopCurrencyGraph = () => {
const historicalAddr = `http://${
process.env.back || "localhost:8000"
}/historical24hChangeData`;
useEffect(() => {
const map: { [name: string]: graphPoint[] } = {};
axios
.get(historicalAddr)
.then((res) => {
const { points } = res.data;
const pointList = points as dataPoint[];
pointList.forEach((obj) => {
const newPoint = {
x: new Date(obj.timestamp).getTime() * (60 * 24),
y: obj.percentage * 100,
};
if (obj.currency in map) {
map[obj.currency].push(newPoint);
} else {
map[obj.currency] = [newPoint];
}
});
})
.catch((err) => {
console.log(err, historicalAddr);
});
const chart = lightningChart().ChartXY({
theme: Themes.lightNew,
container: "currency-graph",
});
chart.setTitle("Top Currencies");
chart.getDefaultAxisX().setTitle("Time");
chart.getDefaultAxisY().setTitle("Percentage Change");
const entries = Object.entries(map);
const names = entries.map(([a, _b]) => a);
const lists = entries.map(([_, b]) => b);
const seriesArray = new Array(5).fill(null).map((_, idx) =>
chart
.addLineSeries({
dataPattern: {
pattern: "ProgressiveX",
},
})
// eslint-disable-next-line arrow-parens
.setStrokeStyle((stroke) => stroke.setThickness(1))
.setName(names[idx])
);
seriesArray.forEach((series, idx) => {
if (idx === 1) {
series.add(lists[idx]);
}
});
chart.addLegendBox(LegendBoxBuilders.HorizontalLegendBox).add(chart);
return () => {
chart.dispose();
};
}, []);
// done thnx
return (
<div className="graph-container">
<div id="currency-graph" className="graph-container"></div>
</div>
);
};
export default TopCurrencyGraph;
Your code looks syntax wise correct, but I believe you are running into issues due to not managing asynchronous code (axios getting data from your endpoint) properly.
const map: { [name: string]: graphPoint[] } = {};
axios
.get(historicalAddr)
.then((res) => {
// This code is NOT executed immediately, but only after some time later.
...
})
// This code and everything below is executed BEFORE the code inside `then` block.
// Because of this, you end up supplying `undefined` or other incorrect values to series / charts which shows as errors.
const chart = lightningChart().ChartXY({
theme: Themes.lightNew,
container: "currency-graph",
});
You might find it useful to debug the values you supply to series, for example like below. I think the values are not what you would expect.
seriesArray.forEach((series, idx) => {
if (idx === 1) {
console.log('series.add', lists[idx])
series.add(lists[idx]);
}
});
Improvement suggestion
Here's my attempt at modifying the code you supplied to manage the asynchronous data loading correctly, by moving all code that relies on the data after the data is processed.
/* eslint-disable new-cap */
/* eslint-disable #typescript-eslint/no-unused-vars */
/* eslint-disable no-magic-numbers */
import React, { useEffect, useState } from "react";
import { LegendBoxBuilders, lightningChart, Themes } from "#arction/lcjs";
import "./TopCurrencyGraph.css";
import axios from "axios";
export interface data {
data: dataPoint[];
}
export interface dataPoint {
currency: string;
percentage: number;
timestamp: string;
}
interface graphPoint {
x: number;
y: number;
}
const TopCurrencyGraph = () => {
const historicalAddr = `http://${
process.env.back || "localhost:8000"
}/historical24hChangeData`;
useEffect(() => {
const chart = lightningChart().ChartXY({
theme: Themes.lightNew,
container: "currency-graph",
});
chart.setTitle("Top Currencies");
chart.getDefaultAxisX().setTitle("Time");
chart.getDefaultAxisY().setTitle("Percentage Change");
const seriesArray = new Array(5).fill(null).map((_, idx) =>
chart
.addLineSeries({
dataPattern: {
pattern: "ProgressiveX",
},
})
// eslint-disable-next-line arrow-parens
.setStrokeStyle((stroke) => stroke.setThickness(1))
);
chart.addLegendBox(LegendBoxBuilders.HorizontalLegendBox).add(chart);
axios
.get(historicalAddr)
.then((res) => {
const { points } = res.data;
const pointList = points as dataPoint[];
const map: { [name: string]: graphPoint[] } = {};
pointList.forEach((obj) => {
const newPoint = {
x: new Date(obj.timestamp).getTime() * (60 * 24),
y: obj.percentage * 100,
};
if (obj.currency in map) {
map[obj.currency].push(newPoint);
} else {
map[obj.currency] = [newPoint];
}
});
const entries = Object.entries(map);
const names = entries.map(([a, _b]) => a);
const lists = entries.map(([_, b]) => b);
seriesArray.forEach((series, idx) => {
series.setName(names[idx])
if (idx === 1) {
series.add(lists[idx]);
}
});
})
.catch((err) => {
console.log(err, historicalAddr);
});
return () => {
chart.dispose();
};
}, []);
// done thnx
return (
<div className="graph-container">
<div id="currency-graph" className="graph-container"></div>
</div>
);
};
export default TopCurrencyGraph;
I have hosted a peer to peer meeting react app on netlify. I have used Peerjs for my video purpose. Everything is working as expected except the video. For some networks the video of the the remote person is working and for some others it is not working. I looked up and found out that it may be a STUN/TURN issue. I then implemented all the STUN/TURN servers in my code. However the video is still not getting setup in some cases. In some cases it is working fine, in others the video is not showing up. Herewith, I am attaching th code for the video and the link to the site.
import React,{useEffect,useState} from 'react';
import {io} from "socket.io-client";
import {useParams} from 'react-router-dom';
import {Grid} from "#material-ui/core";
import Peer from 'peerjs';
var connectionOptions = {
"force new connection" : true,
"reconnectionAttempts": "Infinity",
"timeout" : 10000,
"transports" : ["websocket"]
};
const Videobox = ({isVideoMute,isAudioMute}) => {
var myPeer = new Peer(
{
config: {'iceServers': [
{urls:'stun:stun01.sipphone.com'},
{urls:'stun:stun.ekiga.net'},
{urls:'stun:stun.fwdnet.net'},
{urls:'stun:stun.ideasip.com'},
{urls:'stun:stun.iptel.org'},
{urls:'stun:stun.rixtelecom.se'},
{urls:'stun:stun.schlund.de'},
{urls:'stun:stun.l.google.com:19302'},
{urls:'stun:stun1.l.google.com:19302'},
{urls:'stun:stun2.l.google.com:19302'},
{urls:'stun:stun3.l.google.com:19302'},
{urls:'stun:stun4.l.google.com:19302'},
{urls:'stun:stunserver.org'},
{urls:'stun:stun.softjoys.com'},
{urls:'stun:stun.voiparound.com'},
{urls:'stun:stun.voipbuster.com'},
{urls:'stun:stun.voipstunt.com'},
{urls:'stun:stun.voxgratia.org'},
{urls:'stun:stun.xten.com'},
{
urls: 'turn:numb.viagenie.ca',
credential: 'muazkh',
username: 'webrtc#live.com'
},
{
urls: 'turn:192.158.29.39:3478?transport=udp',
credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
username: '28224511:1379330808'
},
{
urls: 'turn:192.158.29.39:3478?transport=tcp',
credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
username: '28224511:1379330808'
}
]} /* Sample servers, please use appropriate ones */
}
);
const peers = {}
const [socket, setSocket] = useState()
const {id:videoId} = useParams();
const videoGrid = document.getElementById('video-grid')
useEffect(()=> {
const s=io("https://weconnectbackend.herokuapp.com",connectionOptions);
setSocket(s);
return () => {
s.disconnect();
}
},[])
// let myVideoStream;
const [myVideoStream, setmyVideoStream] = useState()
const muteUnmute = () => {
const enabled = myVideoStream.getAudioTracks()[0].enabled;
if (enabled) {
myVideoStream.getAudioTracks()[0].enabled = false;
//setUnmuteButton();
} else {
//setMuteButton();
myVideoStream.getAudioTracks()[0].enabled = true;
}
}
const playStop = () => {
//console.log('object')
let enabled = myVideoStream.getVideoTracks()[0].enabled;
if (enabled) {
myVideoStream.getVideoTracks()[0].enabled = false;
//setPlayVideo()
} else {
//setStopVideo()
myVideoStream.getVideoTracks()[0].enabled = true;
}
}
useEffect(() => {
if(myVideoStream)
playStop()
}, [isVideoMute])
useEffect(() => {
if(myVideoStream)
muteUnmute()
}, [isAudioMute])
useEffect(() => {
if(socket== null)
return;
myPeer.on('open',id=>{
socket.emit('join-room',videoId,id);
})
const myVideo = document.createElement('video')
myVideo.muted = true
navigator.mediaDevices.getUserMedia({
video: true,
audio: true
}).then(stream => {
// myVideoStream = stream;
window.localStream=stream;
setmyVideoStream(stream);
console.log(myVideoStream,"myvideostream");
addVideoStream(myVideo, stream)
myPeer.on('call', call => {
call.answer(stream)
const video = document.createElement('video')
call.on('stream', userVideoStream => {
addVideoStream(video, userVideoStream)
})
})
socket.on('user-connected',userId =>{
connectToNewUser(userId, stream)
})
socket.on('user-disconnected', userId => {
if (peers[userId]) peers[userId].close()
})
})
}, [socket,videoId])
function addVideoStream(video, stream) {
video.srcObject = stream
video.addEventListener('loadedmetadata', () => {
video.play()
})
videoGrid.append(video)
}
function connectToNewUser(userId, stream) {
const call = myPeer.call(userId, stream)
const video = document.createElement('video')
call.on('stream', userVideoStream => {
addVideoStream(video, userVideoStream)
})
call.on('close', () => {
video.remove()
})
peers[userId] = call
}
return (
<div id="video-grid" className="videoStyleFromDiv">
{/* <Video srcObject={srcObject}/> */}
</div>
)
}
export default Videobox
Website Link
The TURN servers you are using have been out of commission for a couple of years in the case of the ones taken from https://www.html5rocks.com/en/tutorials/webrtc/infrastructure/
Copying credentials from random places is not how TURN works, you will need to run your own servers.
My component works fine and I can see it is working properly with the maps being formed in UI and markers coming up properly, however I am still get this error for the challenge :
Challenge Not yet complete... here's what's wrong:
We can't find the correct settings for the createMapMarkers() function in the component boatsNearMe JavaScript file. Make sure the component was created according to the requirements, including the right mapMarkers, title, Latitude (Geolocation__Latitude__s), Longitude (Geolocation__Longitude__s), the correct constants, stopping the loading spinner, and using the proper case-sensitivity and consistent quotation.
This is the Challenge 7 Statement as per the trailhead:
"Build the component boatsNearMe and display boats near you
Create the component boatsNearMe and show boats that are near the user, using the browser location and boat type. Display them on a map, always with the consent of the user (and only while the page is open)."
https://trailhead.salesforce.com/en/content/learn/superbadges/superbadge_lwc_specialist
Here is my boatsNearMe LWC code
import { LightningElement, wire, api } from 'lwc';
import getBoatsByLocation from '#salesforce/apex/BoatDataService.getBoatsByLocation';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
const LABEL_YOU_ARE_HERE = 'You are here!';
const ICON_STANDARD_USER = 'standard:user';
const ERROR_TITLE = 'Error loading Boats Near Me';
const ERROR_VARIANT = 'error';
export default class BoatsNearMe extends LightningElement {
#api boatTypeId;
mapMarkers = [];
isLoading = true;
isRendered = false;
latitude;
longitude;
#wire(getBoatsByLocation, { latitude: '$latitude', longitude: '$longitude', boatTypeId: '$boatTypeId' })
wiredBoatsJSON({ error, data }) {
if (data) {
this.isLoading = true;
this.createMapMarkers(JSON.parse(data));
} else if (error) {
this.dispatchEvent(
new ShowToastEvent({
title: ERROR_TITLE,
message: error.body.message,
variant: ERROR_VARIANT
})
);
// this.isLoading = false;
}
}
getLocationFromBrowser() {
navigator.geolocation.getCurrentPosition(
position => {
this.latitude = position.coords.latitude;
this.longitude = position.coords.longitude;
},
(error) => {}
);
}
createMapMarkers(boatData) {
const newMarkers = boatData.map((boat) => {
return {
location: {
Latitude: boat.Geolocation__Latitude__s,
Longitude: boat.Geolocation__Latitude__s
},
title: boat.Name,
};
});
newMarkers.unshift({
location: {
Latitude: this.latitude,
Longitude: this.longitude
},
title: LABEL_YOU_ARE_HERE,
icon: ICON_STANDARD_USER
});
this.mapMarkers = newMarkers;
this.isLoading = false;
}
renderedCallback() {
if (this.isRendered == false) {
this.getLocationFromBrowser();
}
this.isRendered = true;
}
}
I think you have Geolocation__Latitude__s twice in this part:
createMapMarkers(boatData) {
const newMarkers = boatData.map((boat) => {
return {
location: {
Latitude: boat.Geolocation__Latitude__s,
Longitude: boat.Geolocation__Latitude__s // <<-- should be Longitude
},
title: boat.Name,
};
});
I am student who is creating a big project trying to display data and information on maps using Openlayers and React. At this point I have created a basic two page project where the map is the central piece of the application. For every page I have one main Component that contains its Sidebar, the Viewer Component that contains the map itself and some additional Components specific for that page.
The viewer Class is a special Component that I wrote for every page. This Component handles all the user interactions with the page. It sends and receives information from the main Component as well. I have chosen to create a seperate Viewer Class for each page beceause of the diffrent ways each page works. They might load in different things or handle interactions completely different. If I had one Viewer Class that can be used by every page this would become to large and have to many if statements to check what code to run when handling with each separate page.
Here is an example of the Homepage Viewer. In the constructor I create the map and add some references for a popup window that shows up when the user clicks on one of the features on the map. This popup window shows some basic information about the feature and let's the user add it to his list of features.
In ComponentDidMount I first make the Map class add the
boundrieslayer and give an function to call when one of the feautres
of this layer has been clicked on. I also create the overlay window
for the popup to the map. This will be shown when a feature has been
clicked.
resetMapLayers is a function that has will be called on each Render.
Here I make the map check if what background Tilelayer to use and if
it should show the top layer or not.
featureSelected() is the function that handles a click event of a
feature of the top layer. This will create a popup with the basic
information of the feature.
closePopup will be called when the popup has been closed. This will
make the map deselct the clicked on feature. Otherwise it would stay
selected when the popup has been closed. It will also remove the
Overlay(popup) from the screen.
addFeature() is the function that will be called when a user chooses
to add this feature to his list of features. This can be done by the
user in the popup window of that feature
.
import React, { Component } from "react";
import { connect } from "react-redux";
import Map from "../Map/Map";
import "ol/ol.css";
import styles from "./Viewer.module.scss";
import Overlay from "ol/Overlay";
import Button from "../UI/Button/Button";
class MainViewer extends Component {
constructor(props) {
super(props);
Map.createNewMap();
this.popup = React.createRef();
this.popupContent = React.createRef();
}
componentDidMount() {
Map.addBoundriesLayer(this.featureSelected);
Map.map.setTarget("map");
let container = this.popup.current;
let overlay = new Overlay({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250,
},
});
this.overlay = overlay;
Map.map.addOverlay(overlay);
}
resetMapLayers() {
Map.setBackgroundTileLayer(this.props.type);
Map.togglePlotBoundriesLayers(this.props.plotBoundriesState);
}
featureSelected = (event, select) => {
if (event.selected[0]) {
this.selectedFeature = event.selected[0];
let selectedFeature = {
id: event.selected[0].id_,
gewasgroepnaam: event.selected[0].getProperties().GEWASGROEP,
gewasnaam: event.selected[0].getProperties().LBLHFDTLT,
oppervlak: (event.selected[0].getProperties().OPPERVL / 10000).toFixed(
2
),
coords: event.selected[0].getProperties().geometry.extent_,
};
let content = this.popupContent.current;
content.innerHTML =
"<p><strong>Name: </strong>" +
selectedFeature.name +
"</p>" +
"<p><strong>Exact Name: </strong>" +
selectedFeature.exactName +
"</p>" +
"<p><strong>Area: </strong>" +
selectedFeature.area +
" ha</p>";
this.overlay.setPosition(event.mapBrowserEvent.coordinate);
}
};
closePopup() {
this.overlay.setPosition(undefined);
Map.clearSelect();
return false;
}
addFeature() {
this.overlay.setPosition(undefined);
Map.clearSelect();
this.props.featureAddedHandler(this.selectedFeature);
}
render() {
this.resetMapLayers();
return (
<div>
<div id="map" className={styles.Map}></div>
<div ref={this.popup} className={styles.OlPopup}>
<div className={styles.OlPopupButtonsDiv}>
<Button
btnType="Danger"
className={[styles.PopupButton, styles.ClosePopupButton].join(
" "
)}
clicked={() => this.closePopup()}
>
Annuleer
</Button>
<Button
btnType="Success"
className={[styles.PopupButton, styles.AddPopupButton].join(" ")}
clicked={() => this.addFeature()}
>
Voeg Toe
</Button>
</div>
<div ref={this.popupContent}></div>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
type: state.mapDetails.type,
plotBoundriesState: state.mapDetails.state,
};
};
export default connect(mapStateToProps)(MainViewer);
The Map class contains the actual map. It handles with all the specific map issues. It allows to add layers to the map, creating the initial map, adding map interactions,...
In the constructor I call the methods to initaly create a basic map
with a TileLayer background.
The createMap and createNewMap methods let's me create the map object
itself.
createBackgroundLayerGroups() creates the Tilelayer that is the
background layer. It can be either OSM or Bing Maps. The visibility
property let's me make handle which one to show.
clearAllBoundriesLayers() deletes all the boundries layers that are
able to be put on top of the Tilelayer. It deletes every layer and
clears the select of the interactions that has been added to these
layers. I do this so when I change page the layers will be deleted.
addBoundriesLayer let's me set and add a boundries layer. This is the
Vector layer that will be put on top of the TileLayer.
addUsersPlotBoundriesLayer does the same as "addBoundriesLayer" but does it for all the layers that the user has. This function will be called in another page that only shows the features of the user.
setExtentOfMapByUserFeaters let's me set the extent of the map by
either a given extent or by the features of the user.
setInteractionForPlotBoundriesLayer adds the interaction for the
PlotBoundriesLayer.
setHoverInteractionForUserPlotBoundries adds the hover interaction
for the plotUserBoundriesLayer.
clearSelect clears all the selected features. So they won't be
highlighted no more.
setBackgroundTileLayer let's me show a specific background TileLayer.
togglePlotBoundriesLayers let's me hide or show the Vector layer that
is then been shown.
import Map from "ol/Map";
import TileWMS from "ol/source/TileWMS";
import TileLayer from "ol/layer/Tile";
import View from "ol/View";
import OSM from "ol/source/OSM";
import BingMaps from "ol/source/BingMaps";
import VectorSource from "ol/source/Vector";
import { bbox as bboxStrategy } from "ol/loadingstrategy";
import GeoJSON from "ol/format/GeoJSON";
import { Vector, Group, Tile } from "ol/layer";
import Select from "ol/interaction/Select";
import { Feature } from "ol";
import { Polygon } from "ol/geom";
import { Fill, Stroke, Style } from "ol/style";
class OlMap {
constructor() {
this.createNewMap();
this.createBackgroundLayerGroups();
}
createNewMap() {
this.map = this.createMap();
}
createMap() {
return new Map({
target: null,
layers: [],
view: new View({
center: [594668.0262129545, 6602083.305674396],
maxZoom: 19,
zoom: 14,
}),
});
}
createBackgroundLayerGroups() {
this.layersOSM = new Group({
layers: [
new Tile({
source: new OSM(),
}),
new Tile({
source: new BingMaps({
imagerySet: "Aerial",
key: process.env.REACT_APP_BING_MAPS,
}),
visible: false,
}),
],
});
}
clearAllBoundriesLayers() {
this.map.getLayers().forEach((layer) => {
if (
layer.get("name") === "plotBoundriesLayer" ||
layer.get("name") === "plotUserBoundriesLayer"
) {
layer.getSource().clear();
this.map.removeLayer(layer);
}
});
if (this.select) {
this.select.getFeatures().clear();
}
}
addBoundriesLayer(featureSelected) {
this.clearAllBoundriesLayers();
let vectorSource = new VectorSource({
format: new GeoJSON(),
minScale: 15000000,
loader: function (extent, resolution, projection) {
/*
Link for the DLV
let url = process.env.REACT_APP_MAP_API +
extent.join(",") +
",EPSG:3857";
*/ let url = process.env.REACT_APP_MAP_API +
extent.join(",") +
",EPSG:3857";
// */
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
let onError = function () {
vectorSource.removeLoadedExtent(extent);
};
xhr.onerror = onError;
xhr.onload = function () {
if (xhr.status === 200) {
let features = vectorSource
.getFormat()
.readFeatures(xhr.responseText);
features.forEach(function (feature) {
//ID for the DLV
//feature.setId(feature.get("OBJ_ID"));
feature.setId(feature.get("OIDN"));
});
vectorSource.addFeatures(features);
} else {
onError();
}
};
xhr.send();
},
strategy: bboxStrategy,
});
let vector = new Vector({
//minZoom: 13,
source: vectorSource,
});
this.setInteractionForPlotBoundriesLayer(vector, featureSelected);
vector.set("name", "plotBoundriesLayer");
this.map.addLayer(vector);
}
addUsersPlotBoundriesLayer(featureSelected, featureHovered, newFeatures) {
this.clearAllBoundriesLayers();
if (newFeatures.length > 0) {
let vectorSource = new VectorSource({
format: new GeoJSON(),
minScale: 15000000,
strategy: bboxStrategy,
});
newFeatures.forEach((newFeature) => {
let feature = new Feature({
geometry: new Polygon([newFeature.geometry]),
});
feature.setId(newFeature.plotId);
vectorSource.addFeature(feature);
});
let vector = new Vector({
//minZoom: 13,
source: vectorSource,
});
this.setInteractionForPlotBoundriesLayer(vector, featureSelected);
this.setHoverInteractionForUserPlotBoundries(vector, featureHovered);
vector.set("name", "plotUserBoundriesLayer");
this.plotsExtent = vectorSource.getExtent();
this.map.addLayer(vector);
}
}
setExtentOfMapByUserFeaters(extent) {
if (extent === undefined) {
if (this.plotsExtent !== undefined && this.plotsExtent[0] !== Infinity) {
this.map.getView().fit(this.plotsExtent);
}
} else {
this.map.getView().fit(extent);
}
}
setInteractionForPlotBoundriesLayer(layer, featureSelected) {
this.select = new Select({
layers: [layer],
});
this.select.on("select", (event) => featureSelected(event, this.select));
this.map.addInteraction(this.select);
}
setHoverInteractionForUserPlotBoundries(layer, featureHovered) {
this.hoveredFeature = null;
let defaultStyle = new Style({
stroke: new Stroke({
width: 2,
color: "#9c1616",
}),
fill: new Fill({ color: "#c04e4e" }),
});
let hoveredStyle = new Style({
stroke: new Stroke({
width: 2,
color: "#9c1616",
}),
fill: new Fill({ color: "#9c1616" }),
});
this.map.on("pointermove", (e) => {
layer
.getSource()
.getFeatures()
.forEach((feature) => {
feature.setStyle(defaultStyle);
});
let newFeature = null;
this.map.forEachFeatureAtPixel(e.pixel, (f) => {
newFeature = f;
newFeature.setStyle(hoveredStyle);
return true;
});
if (newFeature) {
if (
this.hoveredFeature === null ||
this.hoveredFeature !== newFeature
) {
this.hoveredFeature = newFeature;
featureHovered(this.hoveredFeature.id_);
}
} else {
if (this.hoveredFeature !== null) {
this.hoveredFeature = null;
featureHovered(null);
}
}
});
}
hoveredSideBarFeatureHandler(hoveredFeatureId) {
let defaultStyle = new Style({
stroke: new Stroke({
width: 2,
color: "#9c1616",
}),
fill: new Fill({ color: "#c04e4e" }),
});
let hoveredStyle = new Style({
stroke: new Stroke({
width: 2,
color: "#9c1616",
}),
fill: new Fill({ color: "#9c1616" }),
});
this.map.getLayers().forEach((layer) => {
if (layer.get("name") === "plotUserBoundriesLayer") {
layer
.getSource()
.getFeatures()
.forEach((feature) => {
if (feature.id_ === hoveredFeatureId) {
feature.setStyle(hoveredStyle);
} else {
feature.setStyle(defaultStyle);
}
});
}
});
}
clearSelect() {
this.select.getFeatures().clear();
}
setBackgroundTileLayer(type) {
if (this.backgroundTileType === null) {
this.backgroundTileType = "OPENSTREETMAP";
}
if (this.map.getLayers().getArray().length === 0) {
this.map.setLayerGroup(this.layersOSM);
} else {
if (this.backgroundTileType !== type) {
this.backgroundTileType = type;
console.log(this.map.getLayers());
this.map.getLayers().getArray()[0].setVisible(false);
this.map.getLayers().getArray()[1].setVisible(false);
if (type === "OPENSTREETMAP") {
this.map.getLayers().getArray()[0].setVisible(true);
} else if (type === "BING MAPS") {
this.map.getLayers().getArray()[1].setVisible(true);
}
}
}
}
togglePlotBoundriesLayers(state) {
if (this.plotBoundriesState === null) {
this.plotBoundriesState = true;
}
if (this.plotBoundriesState !== state) {
this.plotBoundriesState = state;
this.map.getLayers().forEach((layer) => {
if (layer.get("name") === "plotBoundriesLayer") {
layer.setVisible(state);
}
if (layer.get("name") === "plotUserBoundriesLayer") {
console.log(state);
layer.setVisible(state);
}
});
}
}
addTileLayer(url) {
const wmsLayer = new TileLayer({
source: new TileWMS({
url,
params: {
TILED: true,
},
crossOrigin: "Anonymous",
}),
});
this.map.addLayer(wmsLayer);
}
}
export default new OlMap();
At this point I am wondering if I am doing things well or what can be done different or better to optimize my code. This will help me in the long run not getting stuck with bade code I created at the beginning of the project.
Many thanks in advance!