Closed jtlan closed 10 years ago
So to start this discussion. One thing that I think was 75% resolved is why are Interactions objects instead of inherently attached? Is it strictly so we have ideas of reusability and encapsulation?
The API proposal seems very hand-wavey and incomplete. Could you please flesh it out some more.
@danmane I'll definitely fill those in. I hadn't finished fleshing out that page yet.
I proposed this interface on the wiki page:
export interface Hoverable {
getHovered: (p: Point) => HoverData;
}
export interface HoverData {
tooltipTarget: D3.Selection;
data: any;
}
but I actually don't feel too good about the signature there; the return type is pretty clunky. Anyone have ideas on how to generalize the signature?
@jtlan In regards to your sample use case, could the selection be null? Is there a way to enforce that the function is never called when it is null?
The selection could be null if there's nothing under the cursor. The issue here is that I'm trying to roll up complicated callback construction so the user doesn't have to build one. Maybe the correct approach is to create methods that generate callbacks, rather than trying to build them in. Currently the user has to do something like this:
var hoverInteraction = new Plottable.Interaction.Hover();
var hoverCallback = function(point) {
var bar = barPlot.selectBar(point.x, point.y, null);
if (bar != null) {
// logic to draw tooltip, etc
}
};
hoverInteraction.onHover(hoverCallback);
barPlot.registerInteraction(hoverInteraction);
So I guess I'm still confused on why Interactions are objects instead of strict interfaces. When I create an interaction, for example, I almost always expect it to be coupled with some component/element from the getgo (Examples of this workflow include jQuery's click, hover, etc.). I remember @danmane saying that one advantage is that there will be lack of duplication if we use objects, but I am currently failing to see this advantage in the current proposed architecture.
Also, I think I'm misunderstanding a possible workflow that's listed in the wiki
class LegendHoverInteraction extends HoverInteraction {
onHover() { doHoverStuff }
}
class Legend implements Hoverable {
getHovered() { doHoverStuff }
}
What's the difference between the two? Does attaching the LegendHoverInteraction to Legend just enable getHovered to activate? If so, LegendHoverInteraction seems to be a simple switch...?
Interactivity is designed as Interaction
objects rather than interfaces in order to make the behavior more reusable, and to allow novel combinations of interactions in a way that we didn't necessarily anticipate when writing the library. We could build interactions as mixins, so you get something like this:
class Dragabble { // Implementation }
class Hoverable { // Implementation }
class Zoomable { // Implementation }
public class Scatter extends Plot implements Draggable, Hoverable, Zoomable {
...
}
But what happens when someone wants a scatterplot to respond to a click? Or a keypress? Do they have to modify the library?
public class Scatter extends Plot implements Draggable, Hoverable, Zoomable, Clickable, KeyPressAble {
...
}
Essentially this approach requires that we exhaustively list the available choices for interactivity, which constrains the user's flexibility.
I still don't understand your comment about LegendHoverInteraction extends HoverInteraction
. We would either have LegendHoverInteraction
or have Legend
implement Hoverable
and supply its own custom logic, not both.
So after thinking about this some more and looking at the wiki after it's updated, I see the DragBoxHandler interface. From a brief implementation perspective, how are the arguments being piped through to the callback? I remember on an earlier wiki that there was a getHovered function attached to components that are Hoverable. Is that where the information is gathered?
Implementation nitpick - Should we put data at the forefront to highlight that the data should be the main variable to interface for whatever handler?
I think it'd be great if we can find a way to avoid custom handlers. This means we have to discuss / figure out 2 things. Narrow down the scope of a handler / generalize the handler across components that will react from the handler.
Let's use tooltips as an example. I can imagine tooltips being implemented as... a mouseInteraction where if you mouseOver a location then a tooltip will show with relevant data and the tooltip will fade on mouseOut.
Now, what does this require? Ignoring the Interaction aspect (I can imagine a mouseInteraction which is essentially a housing for handlers where relevant data is fed to it), what should the behavior be? In the most general case, it seems we should create some tooltip element based on input data and mouse location. Based on the previous sentence, we won't need a PiePlotTooltipHandler or anything such. A single TooltipHandler should be able to do the work.
In other words, we shouldn't need to create a handler for each component to cover 1 task across all components. In the structure I'm thinking, every class might need to implement a function to provide the correct information, but that should be all
Discussion concluded. I'll update the wiki.
Associated discussion thread for Interaction API Proposal.