React Firebase, realtime cursor position watcher can't handle updates - reactjs

I am writing a module that lets you track your mouse coordinates on another person his screen. I am writing the X and Y coordinates to firebase. The `onMouseMove write event goes really smooth and Firebase updates perfectly fine without lag. However my read event has some trouble keeping up:
.child('activity')
.on('value', snapshot => {
if (snapshot.val()) {
friendDashboardActivityData[userKey] = snapshot.val();
if (document.getElementById('cursor' + userKey)) {
/** Place the element based on the coordinates */
let d = document.getElementById('cursor' + userKey);
d.style.left = snapshot.val()['cursor'].x + 'px';
d.style.top = snapshot.val()['cursor'].y + 'px';
The mouse that appears on screen is really laggy because it can't handle the many changes per second in firebase. Is there a socket like connector in firebase (or perhaps we made a mistake somewhere) that we can use, so i seems that the cursor is moving smoothly.

Related

Updating folium coordinates on callback in dash app

I am trying to update the coordinates of a folium map rendered by a Dash App on a callback (which is running inside a Flask App). The callback selectively renders different layers on a map - the issue is that the zoom and center coordinates are not persisted when the map is updated. The map is rendered as html and injected as in iframe into the app.
Addendum: Not a professional programmer, have only been trying my hand at this for the past six months.
I have tried three approaches:
JS API call client-side to flask route. I ended up realizing this had too much overhead (plus couldn't identify user to update the proper coordinates).
Encoding the coordinates and zoom in the URL. The URL changes as expected from this js snippet:
map_layer.on("mouseup zoomend", function(){
var coordinates = map_layer.getCenter();
var lat = coordinates.lat
var lon = coordinates.lng
var zoom = map_layer.getZoom();
parent.history.replaceState({}, '', `/app/layer?&lat=${lat}&lon=${lon}&zoom=${zoom}`);
// const ON_CHANGE = '_dashprivate_historychange';
// window.dispatchEvent(new CustomEvent(ON_CHANGE));
// parent.window.dispatchEvent(new CustomEvent(ON_CHANGE));
console.log("success");
The commented-out code also tries to dispatch a CustomEvent to dash to try and update it's history - not really clear what's happening there - just tried to emulate this approach.
The right URL is not passed on to the callback however. So despite the url changing on the browser, it's not being sent back with the updated query variables. If I refresh the page and actively send the URL, than the right URL is passed on, but that's not the kind of behavior I'm looking for - I would like for it to change with no active reloading of the page:
#layer.callback(
Output("map", "srcDoc"),
-- other inputs --,
Input('url', 'href') #tried State as well
)
def update_output_src(href):
print(href)
-- other code --
return map.get_root().render()
Using a hidden DIV to store the coordinates. The div content changes as expected from this js snippet:
map_layer.on("mouseup zoomend", function(){
var coordinates = map_layer.getCenter();
var lat = coordinates.lat
var lon = coordinates.lng
var zoom = map_layer.getZoom();
var latstore = parent.document.getElementById('latstore');
latstore.textContent = lat; #trying different approaches in what's changed to see if dash callback captures it.
var lonstore = parent.document.getElementById('lonstore');
lonstore.innerText = lon;
var zoomstore = parent.document.getElementById('zoomstore');
zoomstore.innerHTML = zoom;
console.log("success");
But again I am not able to capture the stored coordinates when the input is triggered.
#layer.callback(
Output("map", "srcDoc"),
-- other inputs --,
State('latstore', 'children'),
State('lonstore', 'children'),
State('zoomstore', 'children'),
)
def update_output_src(latstore, lonstore, zoomstore):
print(latstore, lonstore, zoomstor)
-- other code --
return map.get_root().render()
Any help or pointer in the right direction for approaches 2 or 3 would be super useful. I have been struggling with this for 3-4 days now and I'm out of ideas.

React - Firebase Realtime Database writing data twice

I am making a project - Gift recommendation using React. At the result page, I am trying to save the values to firebase realtime database from which I'll be fetching later for showing user their past recommendations. The problem is, firebase writes the same values twice. What is the issue? Where am I going wrong? Just to be clear, I did console log, the function runs just once, still the value gets written twice.
Code:
const firebasesent = () => {
if (user !== null) {
const username = String(user.email).split("#")[0];
const userRef = firebase.database().ref("Users/" + username);
const recommendation = {
name,
age,
gender,
relation,
ocassion,
interest1,
interest2,
budget,
title,
};
userRef.push(recommendation);
setSentToFirebase(true);
}
};
sentToFirebase is a state variable which I'm using to make sure that the function runs just once.
Firebase -
A single call to userRef.push(recommendation); will result in only one write to the database. If you see the data showing up multiple times, the most likely reason is that firebasesent is being called multiple times. I recommend setting a breakpoint in the method, running in a debugger, and seeing where (else) it's called from.

React-Amazon Chime: Remote user's video tile turns black when the local video is turned off

I am using Amazon-chime-sdk-js to create a video conferencing service with React JS. I am keeping track of a 'tileStates' array which includes both the local and the remote video tiles. The tileStates array is updated in the 'videoTileDidUpdate' and 'videoTileWasRemoved' methods of the observer. The tiles from the 'tileStates' array are bound to video elements with 'bindVideoElement' method. All the video tiles seem to work perfectly when a user joins the meeting. But when the user turns his camera off, one of the tiles of the remote users in his screen turns black. The occurence of the bug is not consistent, i.e., someone turning the camera off does not gurantee that one of the remote user's video will go black in his screen. Sometimes it occurs, sometimes it does not.
Here are the observer methods in-essence:
videoTileDidUpdate: tileState => {
setState((state)=> {
const { tileStates } = state;
const tileId = parseInt(tileState.tileId, 10);
const index = tileStatesDraft.findIndex(tileState => tileState.tileId === tileId)});
if (index >= 0) {
return;
}
tileStatesDraft.push(tileState);
return { tileStates: tileStatesDraft };
}
videoTileWasRemoved: tileId => {
setState( state => {
const { tileStates } = state;
const tileStatesDraft = [...tileStates];
let index = tileStatesDraft.findIndex(tileState => tileState.tileId === tileId);
if (index >= 0) {
tileStatesDraft.splice(index, 1);
return { tileStates: tileStatesDraft };
}
})
}
The video stream is bounded as follows:
const videoElement = this.videoRef.current;
meeting.meetingSession.audioVideo.bindVideoElement(tile.tileId, videoElement);
The black screen
Here's the sequence that recreates the bug (please keep in mind that the bug does not always recreate; sometimes everything works perfectly):
User A joins the meeting and turns the camera on
User B joins the meeting and turns the camera on...both the users can perfectly see each other
User A turns his camera off. The local tile of A is removed and the video tile of B in the screen of user A turns black
** P.S.- Once the tile of User B turns black in the screen of User A, the tile does not get removed even if User B turns off his camera. i.e., the videoTileWasRemoved is not called in the end of User A for the camera of User B after User B's tile turns black on his side**

My flux store gets re-instantiated on reload

Okay. I'm kinda new to react and I'm having a #1 mayor issue. Can't really find any solution out there.
I've built an app that renders a list of objects. The list comes from my mock API for now. The list of objects is stored inside a store. The store action to fetch the objects is done by the components.
My issue is when showing these objects. When a user clicks show, it renders a page with details on the object. Store-wise this means firing a getSpecific function that retrieves the object, from the store, based on an ID.
This is all fine, the store still has the objects. Until I reload the page. That is when the store gets wiped, a new instance is created (this is my guess). The store is now empty, and getting that specific object is now impossible (in my current implementation).
So, I read somewhere that this is by design. Is the solutions to:
Save the store in local storage, to keep the data?
Make the API call again and get all the objects once again?
And in case 2, when/where is this supposed to happen?
How should a store make sure it always has the expected data?
Any hints?
Some if the implementation:
//List.js
componentDidMount() {
//The fetch offers function will trigger a change event
//which will trigger the listener in componentWillMount
OfferActions.fetchOffers();
}
componentWillMount() {
//Listen for changes in the store
offerStore.addChangeListener(this.retriveOffers);
}
retrieveOffers() {
this.setState({
offers: offerStore.getAll()
});
}
.
//OfferActions.js
fetchOffers(){
let url = 'http://localhost:3001/offers';
axios.get(url).then(function (data) {
dispatch({
actionType: OfferConstants.RECIVE_OFFERS,
payload: data.data
});
});
}
.
//OfferStore.js
var _offers = [];
receiveOffers(payload) {
_offers = payload || [];
this.emitChange();
}
handleActions(action) {
switch (action.actionType) {
case OfferConstants.RECIVE_OFFERS:
{
this.receiveOffers(action.payload);
}
}
}
getAll() {
return _offers;
}
getOffer(requested_id) {
var result = this.getAll().filter(function (offer) {
return offer.id == requested_id;
});
}
.
//Show.js
componentWillMount() {
this.state = {
offer: offerStore.getOffer(this.props.params.id)
};
}
That is correct, redux stores, like any other javascript objects, do not survive a refresh. During a refresh you are resetting the memory of the browser window.
Both of your approaches would work, however I would suggest the following:
Save to local storage only information that is semi persistent such as authentication token, user first name/last name, ui settings, etc.
During app start (or component load), load any auxiliary information such as sales figures, message feeds, and offers. This information generally changes quickly and it makes little sense to cache it in local storage.
For 1. you can utilize the redux-persist middleware. It let's you save to and retrieve from your browser's local storage during app start. (This is just one of many ways to accomplish this).
For 2. your approach makes sense. Load the required data on componentWillMount asynchronously.
Furthermore, regarding being "up-to-date" with data: this entirely depends on your application needs. A few ideas to help you get started exploring your problem domain:
With each request to get offers, also send or save a time stamp. Have the application decide when a time stamp is "too old" and request again.
Implement real time communication, for example socket.io which pushes the data to the client instead of the client requesting it.
Request the data at an interval suitable to your application. You could pass along the last time you requested the information and the server could decide if there is new data available or return an empty response in which case you display the existing data.

lodash debounce not-working (I use it wrongly?), function called multiple times

UPDATE: Answered by myself. Scroll to the end.
My objetive is simple:
I have a google map canvas. User can drag the map, and the program automatically downloads the incidents around the center of the map (and draw the markers).
I have this listener for plugin.google.maps.event.CAMERA_CHANGE events. The thing is, this listener triggers multiple times. Meaning: from the time you tap your finger on the canvas -> dragging in accros the canvas -> to the time you lift your finger ... the event triggers multiple times. Not just when you lift your finger.
Apparently it has a watcher that triggers every N miliseconds.
I dont't want my code to perform that costly downloading data from the server + drawing markers during those interim camera_changes. I want to do it only after the user stop dragging. That means: on the last camera change event received during 5 seconds (I figured that the slowest user takes 5 seconds to drag from corner to the opposite corner of the canvas).
Obviouly I turn to debounce for this need. But it doesn't seem to work. I can see from the logs (X1, X2).... that the function gets called multiple times (around 3-to-4 times, depends on how fast you drag across the canvas).
Indeed, they get called only after I stop dragging. But, they get called in series. All 3-4 of them. With delay of 5 seconds between invocation.
That's not what I expected. I also added invocation to the .cancel method (which I think is superfluous..., because if I understand it correctly, the debounce should've already handled that; cancelling interim-invocations within the timeout).
I also tried throttle (which I think conceptually is not the answer. Debounce should be the answer). Anyway, same issue with throttle.
So, my question: where did I do wrong (in using lodash's debounce)?
Thanks!
var currentPosition = initialPosition();
drawMarkersAroundCenter(map, currentPosition);
var reactOnCameraChanged = function(camera) {
console.log('X1');
console.log('-----');
console.log(JSON.stringify(camera.target));
console.log(JSON.stringify(currentPosition));
console.log('-----');
if (camera.target.lat == currentPosition.lat && camera.target.lng == currentPosition.lng) {
return;
}
currentPosition = camera.target;
drawMarkersAroundCenter(map, currentPosition);
}
var debouncedReactOnCameraChange = lodash.debounce(reactOnCameraChanged, 5000, {
'leading': false,
'trailing': true
});
map.on(plugin.google.maps.event.CAMERA_CHANGE, function(camera) {
debouncedReactOnCameraChange.cancel();
debouncedReactOnCameraChange(camera);
});
--- UPDATE ---
I tried a very simplified scenario of using debounce on nodejs console, it works as I expected. I don't even invoke .cancel in the code below. So what's wrong with the above code? I can't see any difference with this simplified code in the image below.
UPDATE
I tried with this dude method instead of "reactOnCameraChanged":
var dude = function(camera) {
console.log('dude');
}
var debouncedReactOnCameraChange = lodash.debounce(dude, 5000, {
'leading': false,
'trailing': true
});
And I also removed the invocation to .cancel:
map.on(plugin.google.maps.event.CAMERA_CHANGE, function(camera) {
//debouncedReactOnCameraChange.cancel();
debouncedReactOnCameraChange(camera);
});
I can see the 'dude' gets printed only once during those 5 seconds.... So.., something that I do inside reactOnCameraChanged is causing interference ... somehow....
RESOLVED:
See answer below.
This code works:
var currentPosition = latLng;
drawMarkersAroundCenter(map, currentPosition);
var debouncedReactOnCameraChange = lodash.debounce(function(camera) {
console.log('reactOnCameraChanged: ' + JSON.stringify(currentPosition));
drawMarkersAroundCenter(map, currentPosition);
}, 3000, {
'leading': false,
'trailing': true
});
map.on(plugin.google.maps.event.CAMERA_CHANGE, function(camera) {
console.log('CAMERA_CHANGE');
if (camera.target.lat == currentPosition.lat && camera.target.lng == currentPosition.lng) {
console.log('same camera spot');
return;
}
console.log('different camera spot');
currentPosition = camera.target;
debouncedReactOnCameraChange(camera);
});

Resources