In Raphael, I'd like to set the cursor shape when it is not over an element (but is over the Raphael paper. I still want it to change when hovering over certain elements as well.
I want the cursor shape over the paper to depend on a JS condition so it can't just be a simple CSS hover event over the canvas.
Related
I am using QPainter in Qt 5.9 using C++ to make a plot and update it based on mouse events.
I would like to know how to plot an error bar that is something like this:
-
|
-
Of course the gaps shouldn't be there between the vertical and horizontal lines.
I need to be able to drag the error bar around on the plot and obtain the co-ordiantes of the center position of the error bar when the mouse button is released. So far I have made a plot with axes and labels. Not sure how to get the error bar using QPainter or any other Qt lib class.
Please provide some insight on how make/plot the error bars. Is there a simple way to do that in QPainter ?
If you are using QPainter you should implement drag-n-drop yourself. It's not that difficult if you don't have too many objects on your plot.
Here's the basic idea:
First of all render all objects. Than you need to reimplement mousePressEvent and mouseMoveEvent in your plot widget. In mousePressEvent you should check if you've clicked on the draggable object and define this object as currently being dragged. In mouseMoveEvent just move this object (if there is one) by changing its coordinates and rerender plot.
You will probably want to optimize plotting to avoid full plot rerender at each mouse move tick. This can be achieved by plotting rarely changing objects to QPixmap/QImage, than rendering this QPixmap/QImage on widget and than plotting error bars and all other kinds of objects that could change at each mouse move tick over this pixmap. At each repaint you will need to define if you need to replot just error bars (or some other dynamic objects) or all widget. I personally implement this by defining bool needFullRepaint which is set to false by widget after each render tick and is set to true after some data inside widget changed.
This is kinda low-level approach, it will require high level of skill and some time to be spend but you will be awarded with maximum control of the rendering and interactions with the widget, which is not always possible with the QGraphicsScene or QCharts
It's going to be a fairly involved project for someone who hasn't used Qt before.
You will want to use QGraphicsScene in all likelihood, rather than a QPainter example. QGraphicsScenes are way easier than QPainter for interactive examples.
Use QCharts as a starting point, they have examples for how to plot data and then move items as a result. Check out the callout example, in particular, which has you paint a callout labeling the position of the cursor on the graph.
Look at the "Drag and Drop Robot" example from Qt.
All of these are an excellent starting point for how to implement draggable features to create an interactive plot. Qt makes it easy for a generalized sense: however, for many plotting features (at least until QtCharts), Qt was much more difficult than specialized plotting libraries.
I need a small popup be shown when the mouse hovers over series in my QtChart.
Highcharts (Javascript) has some really nice examples like this one:
How can I implement this QtCharts?
I cannot find any documentation on implementing popups.
As far as I know you will have to do it by yourself. I needed exactly the same and used a simple QWidget embedded in a QGraphicsProxyWidget that I added to the QGraphicsScene of the chart view.
QWidget *popup = new MyPopUpWidget;
QChartView v;
QGraphicsProxyWidget *proxy = v.scene()->addWidget(popup);
// if you want a drop shadow you can use QGraphicsDropShadowEffect
QGraphicsDropShadowEffect* shadow = new QGraphicsDropShadowEffect();
shadow->setOffset(0, 4);
shadow->setBlurRadius(8);
proxy->setGraphicsEffect(shadow);
While this is nice and simple, the positioning of the popup is the actual work. All the simple solutions weren't good enough for me. For example there are signals if your mouse hits a QGraphicsItem (all line items of your charts are QGraphicsItems) but they are usually to small and you only want to react on the actual data points, not on the line segments.
You can override your mouseMove(QMouseMoveEvent *) function and always check your mouse position against all data points and adjust your popup (show/hide, positioning). If you have many points that will be slow, so I used a spatial grid and assigned data points to grid cells initially. Then you only need to check against points within the grid cells around your mouse position.
I didn't find a better solution.
I'm making a chess game, where I have a box shaped selector, now I want to select a sprite with that box and move it in a specific location with the selection box.
Any link or code?
You keep track of the position of everything.
Poll for events, see where the mouse is. If in the rectangle of a piece, put the selector on top of the piece (assuming you have colorkeying or alpha). You should be able to listen to keyboard input and move the selector based on that.
When mouse clicks, see where the selector is. Find the piece that's under it, and remember it.
When mouse clicks again, see where the selector is now. Check if moving there is valid. If yes, move the piece you remember to the new position.
Consider a path (which is a line) drawn out with Raphael with a mouseover event that sets the cursor to hover. For a thin path/line it is difficult to hover the mouse over that path.
Is there a way to add an invisible border/padding/boundary to the path so that it is easier to hover over the path?
A really simple way to accomplish that would be as follows:
Duplicate the path you're using as a hover trigger with element.clone
Move the clone in front of the current path with element.insertAfter
Use element.attr to set the clone's opacity to just above 0, so that it is effectively invisible but still receives click events, and to have a stroke-width property equal to the original path's stroke-width + your desired margin;
Add your hover events to the cloned element.
This will give you a invisible path much thicker than the original that is capable of receiving mouse events in place of the original, thinner path.
I've mocked this up here, with a cursor property set so you'll see crosshairs when the mouse is over the surrogate path.
My slider had a child button widget. I have recently changed my gui to send the mouse coordinates as relative to the widget, so if the widget is at 50,50 and the mouse is at 50,50, it will now report as 0,0.
This has created some problems for my slider. When I would drag around the button it would position to value.
The only solution I have thought of is to take the given mouse coordinate, add back the absolute position of the button, then subtract the absolute position of the slider.
I was however hoping for a solution that did not envole absolute positioning.
I used to receive the absolute mouse position, when I did, I positioned it like this:
int mousePos = getOrientation() == AGUI_HORIZONTAL ?
mouseArgs.getPosition().getX() - getAbsolutePosition().getX() :
mouseArgs.getPosition().getY() - getAbsolutePosition().getY();
setValue(positionToValue(mousePos));
mouseArgs gives the mouse position relative to the button. Not relative to the slider, which is what would be needed.
I can obtain the relative locations of the widgets, but I don't think that would do it.
Thanks
Since this is a custom GUI, I'm going to make some assumptions and restate your question to make sure I'm answering your question.
You have a slider widget that contains a thumb widget. The user can click and drag the thumb to reposition it. Your GUI sends mouse notifications to your widgets in local relative space rather than absolute screen space. Your question is how can the thumb widget respond to the mouse events to move itself around without having to use absolute coordinates?
You can do this by changing who's responsibility it is to move the thumb widget. It should be the job of the slider widget to position its thumb widget. By doing it that way, all your coordinates can be in the slider widget's local relative space. Basically it'd be something like (assuming you have some kind of event notification):
When created, the slider widget registers for the various mouse events on its child thumb widget.
When the thumb receives mouse events, it raises the event passing along its local coordinate.
Slider widget receives these events and translates the coordinate from thumb local space to slider local space (i.e., click_x = thumb_x + thumb_mouse_x).
Slider can then use this coordinate, which is in the slider's local relative space, to move the thumb.
In general, parents should be responsible for their children's layout.