I'm calling custom event in this way:
How can I fire custom events on canvas in Fabric JS?
Is there a way to call it continuously like the object:scaling/moving events?
SOLUTION:
I solved this problem using the object:moving event:
canvas.on({'object:moving': handleMovement});
...
var handleMovement = function (event) {
//only when a specific corner was dragged
if (event.target.__corner == 'mb') {
//reset original position
event.target.top = event.target.originalState.top;
event.target.left = event.target.originalState.left;
//do other stuff
}
}
If you need to call the event continuously, you could wrap it in a while loop, or use some sort of timeout.
while (shouldFire) {
canvas.trigger(event);
}
or
setTimeout(triggerEvent, 100);
function triggerEvent() {
canvas.trigger(event);
setTimeout(triggerEvent, 100);
}
However, that might not be ideal for the user (especially the while).
While the object:scaling/moving events may appear to be called continuously, I believe they are simply being called incredibly rapidly in response to user interaction. There's a good event demo on the fabricjs website for looking at this. If you select an object and simply hold it stationary, there are no events fired by the canvas. Instead, the events are only fired in response to user movement, such as dragging the shape around the canvas. So, instead of trying to make the events continuously fired, you could simply listen for small changes in the user's input.
Related
Basically, I'm challenging myself to build something similar to watch2gether, where you can watch youtube videos simultaneously through the Youtube API and Socket.io.
My problem is that there's no way to check if the video has been paused other than utilizing the 'onStateChange' event of the Youtube API.
But since I cannot listen to the CLICK itself rather than the actual pause EVENT, when I emit a pause command and broadcast it via socket, when the player pauses in other sockets, it will fire the event again, and thus I'm not able to track who clicked pause first NOR prevent the pauses from looping.
This is what I currently have:
// CLIENT SIDE
// onStateChange event
function YtStateChange(event) {
if(event.data == YT.PlayerState.PAUSED) {
socket.emit('pausevideo', $user); // I'm passing the current user for future implementations
}
// (...) other states
}
// SERVER SIDE
socket.on('pausevideo', user => {
io.emit('smsg', `${user} paused the video`)
socket.broadcast.emit('pausevideo'); // Here I'm using broadcast to send the pause to all sockets beside the one who first clicked pause, since it already paused from interacting with the iframe
});
// CLIENT SIDE
socket.on('pausevideo', () => {
ytplayer.pauseVideo(); // The problem here is, once it pauses the video, onStateChange obviously fires again and results in an infinite ammount of pauses (as long as theres more than one user in the room)
});
The only possible solution I've thought of is to use a different PLAY/PAUSE button other than the actual Youtube player on the iframe to catch the click events and from there pause the player, but I know countless websites that uses the plain iframe and catch these kind of events, but I couldn't find a way to do it with my current knowledge.
If the goal here is to be able to ignore a YT.PlayerState.PAUSED event when it is specifically caused by you earlier calling ytplayer.pauseVideo(), then you can do that by recording a timestamp when you call ytplayer.pauseVideo() and then checking that timestamp when you get a YT.PlayerState.PAUSED event to see if that paused event was occurring because you just called ytplayer.pauseVideo().
The general concept is like this:
let pauseTime = 0;
const kPauseIgnoreTime = 250; // experiment with what this value should be
// CLIENT SIDE
// onStateChange event
function YtStateChange(event) {
if(event.data == YT.PlayerState.PAUSED) {
// only send pausevideo message if this pause wasn't caused by
// our own call to .pauseVideo()
if (Date.now() - pauseTime > kPauseIgnoreTime) {
socket.emit('pausevideo', $user); // I'm passing the current user for future implementations
}
}
// (...) other states
}
// CLIENT SIDE
socket.on('pausevideo', () => {
pauseTime = Date.now();
ytplayer.pauseVideo();
});
If you have more than one of these in your page, then (rather than a variable like this) you can store the pauseTime on a relevant DOM element related to which player the event is associated with.
You can do some experimentation to see what value is best for kPauseIgnoreTime. It needs to be large enough so that any YT.PlayerState.PAUSED event cause by you specifically calling ytplayer.pauseVideo() is detected, but not so long that it catches a case where someone might be pausing, then unpausing relatively soon after.
I actually found a solution while working around what that guy answered, I'm gonna be posting it in here in case anyone gets stuck with the same problem and ends up here.
Since socket.broadcast.emit doesn't emit to itself, I created a bool ignorePause and made it to be true only when the client received the pause request.
Then I only emit the socket if the pause request wasn't already broadcasted and thus received, and if so, the emit is ignored and the bool is set to false again in case this client/socket pauses the video afterwards.
I have a desktop robot device, which connects to a web browser(chrome) using ble(Bluetooth low energy), I have created a custom event in js code to catch some motion values when the robot moves.
but in pixijs all events are base on mouse move, how can I extend it to adapt my scenarios.
See: https://github.com/pixijs/pixi.js/blob/v6.0.0/packages/interaction/src/InteractionManager.ts#L858
I think that you would need to create your own version of InteractionManager as a plugin, and modify that method addEvents(). You would need to listen to your custom event which is fired when the robot moves.
// instead of:
self.document.addEventListener('mousemove', this.onPointerMove, true);
// do like this:
self.document.addEventListener('my_custom_robot_move', this.onPointerMove, true);
etc.
Normally the InteractionManager is registered here: https://github.com/pixijs/pixi.js/blob/fe7b2191e0311b8174a012366ff21c8e2b6dc153/bundles/pixi.js/src/index.ts#L30 - so you would need to call something like this at beginning of your js code (just after the pixi scripts are loaded probably):
Renderer.registerPlugin('interaction', MyInteractionManager);
I am making a simulation tool, that runs simulation (in a separate thread) over user defined number of iterations, which can be entered in an Edit control on the Ribbon Bar. I would like to reuse it to show current iteration during simulation. I also also put CMFCRibbonProgressBar to show the progress. The Ribbon Bar is created with resource editor.
The question is what is the what to get the progress bar and iteration counter to get timely updated without causing the GUI to become unresponsive?
The conventional way over ON_UPDATE_COMMAND_UI routines requires activity in the window, like moving the mouse.
So I probably need a thread that would update this controls. Things like simply creating a thread and trying to update the controls from or using concurrency::parallel_invoke are not suitable.The former simply doesn't work, the latter works, but causes GUI to freeze.
I store pointers in my document to simplify access to the controls. https://stackoverflow.com/a/25429446?noredirect=1
My general idea is (pseudocode)
beginUpdatingThread()
{
while(simulating)
{
updateEditControl();
updateProgressBar();
sleep_40_ms();//conserves the resorces as there is no sense to update more frequent than 25 times per second
}
}
What is correct way of implementing this?
ASSERT(m_hWnd!=NULL);
MSG msg;
while (simulating)
{
// Handle dialog messages
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if(!IsDialogMessage(&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
I solved this by adding a method to the main window that performs the update. now the thread updating from above continually post messages to the main window to perform the update:
auto h = static_cast<CMainFrame*>(AfxGetMainWnd())->m_hWnd;
//here code for starting simulation in a separate thread
std::thread updating([this,h]{
while (simulating)
{
::PostMessage(h, WM_UPDATE_VISUALS, sumulator.getCurrentIteration(), 0);
std::this_thread::sleep_for(std::chrono::milliseconds(40));
}
::PostMessage(h, WM_UPDATE_VISUALS, num_iterations, 0);
});
updating.detach()
I made a subtle mistake at first by capturing h by reference, which quickly expires
But in the end, the above code does exactly what I wanted to achieve
As per the docs, client events are not delivered to the originator of an event. Is it possible to change this behaviour so that 1 client can send an event and all clients (including the originator) receive it?
Thanks!
This isn't available natively as part of the pusher-js library. Normally the originator of the event would probably just call the function that handles the event after triggering it:
function doTrigger( data ) {
var triggered = pusherInstance.trigger( 'private-channelName', 'eventName', data );
if( triggered ) {
handleTriggeredEvent( data );
}
}
function handleTriggeredEvent( data ) {
// Update UI
}
Alternatively you could manipulate the pusher-js library and change the trigger method to also emit the event on the channel. That way the event originators event handler will also be invoked.
To be honest, this suggestion is probably going to be a bit of a hack (you'd probably need to update the EventDispatcher object) so I think the earlier suggestions is the best solution.
I'm trying to create a modular application in javascript using pusher. Different modules need to bind to the same pusher event and sometimes that event is nested in another event. Furthermore, these modules get loaded at different times depending on DOM events triggered by the user.
So, if one module has some code like
env.pusher.connection.bind('connected', function() {
env.my_channel.bind('private_message',function(data){ ... }
}
And another module comes along and wants to listen to the same private_message event. What happens if I write the same code is that the first bind gets overwritten.
What I'm looking for is a way to implement some kind of listeners, possibly with the option of removing a listener from a channel event.
I've thought of a solution myself. It comprises of the following steps:
keep a dictionary of pusher events
every module that wants to make use of a pusher event should search the dictionary first to see if that event exists and if not, write the code that creates the bind for the first time and add it to the dictionary
when a module creates the bind for the first time, it should also trigger a custom event and pass to it the data that pusher sends at the completion of the pusher event
every module that wants to make use of a pusher event should add a handler to the custom event that is triggered when the pusher event is triggered
If that looks hard to follow, here's some code inside a module that is a rewrite of the code in my question(I've used jQuery because jQuery is succint and has custom events already implemented):
if (typeof(env.pusher_events['my_channel']['private_message']) == 'undefined'){
env.pusher_events['my_channel']['private_message'] = true;
// 'pusher-connected' is defined in another module
// this module depends on that event but for brevity
// I'm not defining the 'connected' event here
$(document).on('pusher-connected', 'body', function(){
env.my_channel.bind('private_message', function(data){
$('body').trigger('pusher-my_channel-private_message', data);
})
})
}
$(document).on('pusher-my_channel-private_message', 'body', function(data){
// do something useful with the data
}
Would love to get some feedback on this (drawbacks etc.)