I've made a map using Bokeh, like the first example on this page, except the user can zoom in/out by scrolling up/down, and can tap circles I've added to the map to select them.
At the moment when the cursor is over the map it's the default arrow. If I click and drag the map the cursor changes to the text cursor for some reason. It doesn't change with any other action.
I'd like to be able to change the cursor appearance so that:
When over the map it's the grab cursor
When dragging the map it's the grabbing cursor
When over a circle it's the pointer cursor
I can achieve (1) with:
.bk { cursor: grab; }
but I'm not sure how to achieve the other two.
Following suggestions from the other post I came with this: (works for Bokeh v1.3.0):
from bokeh.models import CustomJS, HoverTool
from bokeh.plotting import figure, show
p = figure(tools='pan, tap, reset')
p.circle(x=[1,2,3], y=[1,2,3], size=30)
code_pan_start = '''
Bokeh.grabbing = true
var elm = document.getElementsByClassName('bk-canvas-events')[0]
elm.style.cursor = 'grabbing'
'''
code_pan_end = '''
if(Bokeh.grabbing) {
Bokeh.grabbing = false
var elm = document.getElementsByClassName('bk-canvas-events')[0]
elm.style.cursor = 'grab'
}
'''
code_hover = '''
if((Bokeh.grabbing == 'undefined') || !Bokeh.grabbing) {
var elm = document.getElementsByClassName('bk-canvas-events')[0]
if (cb_data.index.indices.length > 0)
elm.style.cursor = 'pointer'
else
elm.style.cursor = 'grab'
}
'''
p.js_on_event('panstart', CustomJS(code = code_pan_start))
p.js_on_event('panend', CustomJS(code = code_pan_end))
p.add_tools(HoverTool(callback = CustomJS(code = code_hover)))
show(p)
You could potentially use the PanStart and PanEnd events to set/reset the cursor on drag operations. I think the hover will be difficult to achieve. Currently there is a callback property on hover tools that can be used trigger JS code when an inspection happens on a point. But it only fires when there is an inspection, there is no corresponding event or hook for "un-inspection" so I am not sure how you would reliably clear the cursor state when the user is no longer hovering over the circle.
Related
I've used 2 objects from CustomAction to add 2 buttons to the toolbar : it works fine (with javascript callback), but now, i would like to show / hide the little blue line under those button when the corresponding tool is activated (=adding the style 'bk-active' to the div corresponding to those buttons) : how to do that ? Is it possible to add a html id to the CustomAction ? or how to get an access to the html div on the javascript side through the Bokeh object or cb_obj or this ?
(it's a standalone file, no server)
Thanks
If you have just one Bokeh document you could give your Div a name attribute and use: var div = Bokeh.documents[0].get_model_by_name('div_name') in JS callback. See example below (works for Bokeh 2.1.1)
from bokeh.models import Div, Button, Column, CustomJS
from bokeh.plotting import show
button = Button(label='Toggle Div Visibility')
div = Div(text = 'Bokeh Div', name = "bokeh_div")
# code = "if (div.visible == true) { div.visible = false; } else { div.visible = true; }"
# button.js_on_click(CustomJS(args = {'div': div}, code = code))
code = "var div = Bokeh.documents[0].get_model_by_name('bokeh_div');
if (div.visible == true) { div.visible = false; } else { div.visible = true; }"
button.js_on_click(CustomJS(code = code))
show(Column(button, div))
Is it possible to click on the chart and drag around like tradingview panning ?
Right now its creating rectangle only.
const chart = lightningChart().ChartXY()
// Method for adding OHLCSeries takes one argument: seriesConstructor.
const ohlcSeries = chart.addOHLCSeries(
// Specify type of figure used
{ seriesConstructor: OHLCFigures.Candlestick }
)
You can pan the chart with right click of the mouse. Right now it's not possible to switch the panning of the chart to left click but we are planning to implement a solution to remap the mouse/touch interactions in future.
You can also remove an axis from the panning interaction by calling axis.setChartInteractionPanByDrag(false).
EDIT:
With the new v3.0.0 release, ChartXY mouse interaction buttons can now be explicitly configured. For example, changing panning to left mouse button, and rectangle zoom/fit to right mouse button:
const lcjs = lightningChart({
overrideInteractionMouseButtons: {
chartXYPanMouseButton: 0,
chartXYRectangleZoomFitMouseButton: 2,
},
})
const chart = lcjs.ChartXY()
I am trying to change the colour of my data points with bokeh. When I use a Hover tool this works fine. However, if I use the same callback function with a select or button tool it does not work. I guess this is beacause the change.emit() does not work in combination with a button or select?
How can I make my customJS work with a select or button tool?
callback3=CustomJS(args=dict(source2=source2,p2=p2),code=''' var source2=source2 var data3 = source2.data;
var color = data3['color'];
var i, n = color.length;
for (i = 0; i < n; ++i) {
color[i] = 'blue';
source2.change.emit();
}
''' )
For my the hoover tool I use:
plot.add_tools(HoverTool(tooltips=None, callback=callback3, renderers=[d],mode='vline'))
For the button:
button = Button(label="Foo", button_type="success")
button.js_on_click(callback3)
When I use an alert in my callback this works also for the button and the select.
I solved the problem. It was not related to the change.emit(). The problem was that I used show separately for the plot and the button.
Within my component, I'm drawing some rectangles as below:
var objGraphics:Graphics=graphics;
objGraphics.drawRect(start, end, total, 5);
objGraphics.endFill();
I need to display a custom tooltip for each rectange when the mouse cursor is hovering over it.
How can I do this? I'm using the MouseMove event to track when the cursor moves over these coordinates (that part is working), but when I change the tooltip text it's not refreshing.
private function this_MOUSE_MOVE(event:MouseEvent):void
{
//...some code to check the coordinates to find out which rectangle the cursor
//is over
//current tooltip is "Rectangle A";
ToolTipManager.destroyToolTip(_myToolTip);
var localPoint:Point=new Point(event.localX, event.localY);
var globalPoint:Point=new Point(localToGlobal(localPoint).x,
localToGlobal(localPoint).y);
//cursor is over Rectangle B, so changing the tooltip;
_myToolTip=ToolTipManager.createToolTip("Rectangle B",
globalPoint.x, globalPoint.y) as ToolTip;
callLater(addChild, [_myToolTip]);
}
Thanks for your help.
EDIT: The problem seems to be with the following line:
ToolTipManager.destroyToolTip(_myToolTip);
If I comment out the preceding line, it will display the new tooltip, but it will keep creating new ones and the old ones never get removed. But if I add that line, it doesn't add any tooltips! Is the code not being executed sequentially, i.e., is the code to remove the tooltip somehow getting executed after the code to add the tooltip?
Assuming what you're adding to the stage, is called "myShape", you could do something like this:
// in your class...
private var var tooltip:Tooltip; // Or whatever your tooltip is
myShape.addEventListener(MouseEvent.MOUSE_OVER, handleOver);
myShape.addEventListener(MouseEvent.MOUSE_OUT, handleOut);
private function handleOver(evt:MouseEvent):void
{
// Show here
// OR
// tooltip = new Tooltip();
// addChild(tooltip);
}
private function handleOut(evt:MouseEvent):void
{
// Hide here
// OR
// removeChild(tooltip);
}
Hope this helps.
I have a several chart components that I have created in Flex. Basically I have set up a special UI that allows the user to select which of these charts they want to print. When they press the print button each of the selected charts is created dynamically then added to a container. Then I send this container off to FlexPrintJob.
i.e.
private function prePrint():void
{
var printSelection:Box = new Box();
printSelection.percentHeight = 100;
printSelection.percentWidth = 100;
printSelection.visible = true;
if (this.chkMyChart1.selected)
{
var rptMyChart1:Chart1Panel = new Chart1Panel();
rptMyChart1.percentHeight = 100;
rptMyChart1.percentWidth = 100;
rptMyChart1.visible = true;
printSelection.addChild(rptMyChart1);
}
print(printSelection);
}
private function print(container:Box):void
{
var job:FlexPrintJob;
job = new FlexPrintJob();
if (job.start()) {
job.addObject(container, FlexPrintJobScaleType.MATCH_WIDTH);
job.send();
}
}
This code works fine if the chart is actually displayed somewhere on the page but adding it dynamically as shown above does not. The print dialog will appear but nothing happens when I press OK.
So I really have two questions:
Is it possible to print flex components/charts when they are not visible on the screen?
If so, how do I do it / what am I doing wrong?
UPDATE:
Well, at least one thing wrong is my use of the percentages in the width and height. Using percentages doesn't really make sense when the Box is not contained in another object. Changing the height and width to fixed values actually allows the printing to progress and solves my initial problem.
printSelection.height = 100;
printSelection.width = 100;
But a new problem arises in that instead of seeing my chart, I see a black box instead. I have previously resolved this issue by setting the background colour of the chart to #FFFFFF but this doesn't seem to be working this time.
UPDATE 2:
I have seen some examples on the adobe site that add the container to the application but don't include it in the layout. This looks like the way to go.
i.e.
printSelection.includeInLayout = false;
addChild(printSelection);
Your component has to be on the stage in order to draw its contents, so you should try something like this:
printSelection.visible = false;
application.addChild(printSelection);
printSelection.width = ..;
printSelection.height = ...;
...
then do the printing
i'm not completely sure, but in one of my application I have to print out a complete Tab Navigator and the only method i have found to print it is to automatically scroll the tabnavigator tab in order to show the component on screen when i add them to the printjob.
In this way they are all printed. Before i created the tabnaviagotr scrolling the print (to PDF) result was a file with all the pages of the tab but only the one visible on screen really printed.