Is there a way to trigger plotselected event without triggering plotclick event? - flot

I need click events in the chart.
But I also need to allow user to select a range to zoom in.
Click events are registered properly. However on doing a selection, it triggers both plotselected and plotclick events.
How do I prevent the plotclick event from being triggered while plotselected is triggered?
Selection plugin: https://github.com/flot/flot/blob/master/jquery.flot.selection.js

Currently no, there's no way to avoid getting both events.
One solution might be to remove the 'clickable' option and instead listen to the 'plotunselected' event, which is triggered by a click without drag.

The problem is plotselected triggering plotclick event.
The following conditional check solved my problem.
$("#graph").bind("plotclick", function (event, pos, item) {
if (item == undefined) return false;
// the rest of the click event here
});

resting's answer didn't quite work for me as my use case needed to handle the plotclick event even if there was no item clicked.
I was able to determine if an event was a plotselection vs plotclick event in the plotclick event handler by setting a variable in the plotselection event handler and then checking it in the plotclick handler:
var plotSelectionEvent = false;
$("#placeholder").bind("plotselected", function (event, ranges) {
plotSelectionEvent = true;
// rest of the plot selection event code
});
$("#placeholder").bind("plotclick", function (event, pos, item) {
// check if this event was originally a plot selection event
// reset the variable and return if it was
if (plotSelectionEvent) {
plotSelectionEvent = false;
return;
}
// rest of the plot selection event code
});

Related

How can I mitigate a race condition between the UI thread and a DispatcherTimer.Tick event?

I believe I have a race condition in this code sample but am unsure how to mitigate it.
My scenario is that XAsync() always runs on the UI thread. Within XAsync(), I set m_importantMemberVariable and then start a timer; there's a 1 second delay before the timer fires.
My concern is the timer's tick event calls a method on m_importantMemberVariable. However, in the 1 second interval between starting the timer and Tick firing, XAsync() could be called again and overwrite m_importantMemberVariable.
Code example:
task<void> BobViewModel::XAsync()
{
return create_task(CreateSomethingAsync())
.then([this](SomethingAsync^ aThing)
{
this->m_importantMemberVariable = aThing;
OnPropertyChanged("ImportantMemberVariable");
// Timer has 1 second delay.
this->m_myDispatcherTimer->Start();
}, task_continuation_context::use_current())
.then([activity](task<void> result)
{
// more continuations...
});
}
void BobViewModel::OnTimerTick(Object^, Object^)
{
// Stopping the timer and detaching the event handler
// so timer only fires once.
m_myDispatcherTimer->Stop();
m_myDispatcherTimer->Tick -= m_impressionTimerToken;
m_myDispatcherTimer = { 0 };
// * Possible race condition *
m_importantMemberVariable->DoImportantThing();
}
Question: Assuming I'm correct about a race condition, is there a way to mitigate it?
My understanding is the tick event would fire on the UI thread so synchronization primitives won't help (as the UI thread would already have access).
All your operations are on the UI thread, so they've already been serialized (synchronized) for you. A simple flag will suffice:
bool m_busy; // set to false in constructor
task<void> BobViewModel::XAsync()
{
if (m_busy)
return;
m_busy = true;
// the rest of your code...
}
void BobViewModel::OnTimerTick(Object^, Object^)
{
m_busy = false;
// the rest of your code...
}
Just make sure you handle any exceptions such that you set m_busy back to false if something goes horribly wrong.
The answer to this question suggests using compare_exchange_strong with a std::atomic to ensure only one thread executes a function at a time. The problems with that approach, for this question, are:
1. The DispatcherTimer Tick event fires outside of the task continuation block, and can fire after the continuation completes.
2. A constraint on this problem is for the timer to only fire once.
Some alternative solutions are:
Use compare_exchange_strong but replace DispatcherTimer with create_delayed_task
Assuming the work doesn't have to happen on the UI thread, you can use create_delayed_task to delay work within a task continuation.
task<void>
BobViewModel::UseImportantVariableAsync(
Object^ importantVariable
)
{
return create_delayed_task(
std::chrono::milliseconds(1000),
[importantVariable]()
{
importantMemberVariable->DoImportantThing();
});
}
Then, from the task continuation, simply:
return UseImportantVariableAsync(m_importantMemberVariable);
Use a lambda for the DispatcherTimer's Tick event and capture 'aThing' from the question's example (instead of referencing the member variable in the handler). To only fire the timer once, assign the DispathcerTimer.Tick handler within a std::call_once block so only the first caller gets to do it.

Outlook Addin ExecuteFunction ribbon button does not complete in Outlook for Windows

When executing a dialog with the dialogApi with an executeFunction ribbon button, the executeFunction event never completes in Outlook for Windows.
In the manifest we call function "x" that triggers the dialog and adds the event handlers.
function x(evt) { _event = evt; ...}
Office.context.ui.displayDialogAsync(settings, function (asyncResult) {
_dialog = asyncResult.dialog;
_dialog.addEventHandler(Office.EventType.DialogMessageReceived, messageHandler);
_dialog.addEventHandler(Office.EventType.DialogEventReceived, eventHandler);
})
function messageHandler() { _event.completed(); }
function eventHandler() { _event.completed(); }
ExecuteFunction loader
Update:
1. In the manifest, there is a ribbon button definition that executes a function. The function accepts an event parameter passed from the ribbon button click and calls the Office.context.ui.displayDialogAsync api to open a dialog. The event parameter is save to a global variable so that it can be called later in the dialog event handlers. When clicking on the ribbon button, the dialog opens normally, however, when the dialog is closed, event.completed does not seem to get called. The attached image runs for about 10-15 minutes.
2. Code snippet is attached from the original posting.
3. Platform used is Outlook 2016 on Windows 10 with IE 11 and Edge
* Strange behavior: for debugging purposes, an arbitrary asynchronous request was being triggered on each of the event handlers. When the request is made before event.completed is called, the event gets completed successfully.
I tested the following code and it works:
var globalEvent;
function eventHandler()
{
globalEvent.completed(true);
}
function dialogCallback(asyncResult)
{
_dialog = asyncResult.value;
_dialog.addEventHandler(Office.EventType.DialogEventReceived, eventHandler);
}
function ExecuteFunctionMailRead1(event)
{
globalEvent = event;
Office.context.ui.displayDialogAsync("http://contoso.com/", {height: 30, width: 20}, dialogCallback);
}
I think the problem is that you need to do:
_dialog = asyncResult.value;
instead of
_dialog = asyncResult.dialog;

Make an event handler seamless?

I have written an event handler under Excel online add-in. It is activated by a button activate, then when a user clicks on another cell or range, the address will be written on a text area myTextArea. The whole thing works.
However, once a new cell is selected, a green loading symbol is shown near the focus; WORKING... is shown on the bottom of Excel; it takes almost 0.5 second.
I am just surprised that it takes time for such a simple action. Does anyone know if it is possible to make this event hander faster? Otherwise, is there any other mean than event handling to make this seamless?
(function() {
"use strict";
Office.initialize = function(reason) {
$(document).ready(function() {
app.initialize();
$('#activate').click(addSelectionChangedEventHandler);
});
}
;
function addSelectionChangedEventHandler() {
Office.context.document.addHandlerAsync(Office.EventType.DocumentSelectionChanged, MyHandler);
}
function MyHandler(eventArgs) {
doStuffWithNewSelection();
}
function doStuffWithNewSelection() {
Excel.run(function(ctx) {
var selectedRange = ctx.workbook.getSelectedRange();
selectedRange.load(["address"]);
return ctx.sync().then(function() {
write(selectedRange.address)
})
}).then(function() {
console.log("done");
}).catch(function(error) {
...
});
}
function write(message) {
document.getElementById("myTextarea").value = message;
}
})();
What you're seeing is network lag. The selection changed event -- once registered -- originates on the server, and triggers the code if Office.js that fires your event handler. Your event handler, in turn, creates a local request for getting the selection Range object and its address, sends it over to the server as part of ctx.sync(), and then waits to hear back from the server before firing the .then.
There's not anything you can do to optimize this flow -- you will pay a pretty high per-transaction cost on Excel Online, and event handlers only add one extra step to that cost. On the other hand, the good news is that the Excel.run/ctx-based model does allow you to batch multiple requests into one, drastically reducing the number of roundtrips that would otherwise be required. That is, fetching the values of 10 different ranges is almost identical in speed to fetching just one; whereas it would be 10 times more expensive if each call were made individually.
Hope this helps!
~ Michael Zlatkovsky, developer on Office Extensibility team, MSFT

EventEmmitter: access the event from within the callback

Can I have access to the name of an event from within the callback which is executed when the event is triggered?
Consider the following example, where I have the same callback (handleEvent)for two differenct events. Now I want to add a conditional statement in the callback based on the event that triggered its execution. Is this possible?
obj.on('start', handleEvent);
obj.on('stop', handleEvent);
function handleEvent() {
// how can I check here if the event that triggers the execution of handleEvent is 'start' or 'stop'
}
What I do at the moment is to pass the event two times with 'emit' - which seems to be working fine, but i don't like to write it twice:
obj.emit('start', 'start', handleEvent);
Try EventEmitter2:
var EventEmitter = require('eventemitter2').EventEmitter2
var emitter = new EventEmitter
emitter.on('test', onEvent)
emitter.emit('test')
function onEvent() {
console.log(this.event)
}
You can do:
obj.on('start', handleEvent.bind({ event: 'start' }));
obj.on('stop', handleEvent.bind({ event: 'stop' }));
function handleEvent() {
if(this.event == 'start') { ///
}

Am I subscribing to YUI Menu events improperly?

I've read and followed YUI's tutorial for subscribing to Menu events. I also looked through the API and bits of the code for Menu, MenuBar, and Custom Events, but the following refuses to work
// oMenuBar is a MenuBar instance with submenus
var buyMenu = oMenuBar.getSubmenus()[1];
// this works
buyMenu.subscribe('show', onShow, {foo: 'bar'}, false);
// using the subscribe method doesn't work
buyMenu.subscribe('mouseOver', onMouseOver, {foo: 'bar'}, false);
// manually attaching a listener doesn't work
YAHOO.util.Event.addListener(buyMenu, 'mouseOver', onMouseOver);
// http://developer.yahoo.com/yui/docs/YAHOO.widget.Menu.html#event_keyPressEvent
// there is a keyPress Event, but no spelling of it will trigger the handler
buyMenu.subscribe('keypress', onShow, {foo: 'bar'}, false);
buyMenu.subscribe('keypressed', onShow, {foo: 'bar'}, false);
buyMenu.subscribe('keyPressed', onShow, {foo: 'bar'}, false);
buyMenu.subscribe('keyPress', onShow, {foo: 'bar'}, false);
Functionally, I'm trying to attach a keyPress listener for each submenu of the MenuBar. I do not want to add Bubbling library as a dependency.
Todd Kloots here, author of the YUI Menu widget. When you are subscribing to DOM-based events, the event name is all lower case. So, for the "mouseover" event, subscribe as follows:
buyMenu.subscribe('mouseover', onMouseOver, {foo: 'bar'}, false);
Regarding your keypress event handler: you are subscribing correctly. However, remember that any key-related event handlers will only fire if the Menu has focus. So, make sure your Menu has focus before testing your key-related event handlers. Also - I would recommend listening for the "keydown" event rather than "keypress" as not all keys result in the firing of the "keypress" event in IE.
If you have any other questions, please direct them to the ydn-javascript Y! Group as I monitor the messages on that group frequently.
I hope that helps.
Todd
Based on my testing, the following will work:
oMenu.subscribe('keypress', function () { alert("I'm your friendly neighborhood keypress listener.")});
but that only fires when the Menu is receiving the keypress event, so it would need to already have focus.
Does onShow point to a function?
eg.
var onShow = function()
{
alert("Click!");
}

Resources