Bokeh, standalone html, access to the div created by a CustomAction to add the style bk-active - bokeh

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))

Related

Removing background image from label in tornadofx

I have two css classes on a tornadofx label bound to a SimpleBooleanProperty. One which has a background image and a blue border and one which has no background image and a yellow border.
Snippet from View containing label:
val switch: SimpleBooleanProperty = SimpleBooleanProperty(false)
label("my label"){
toggleClass(UIAppStyle.style1, switch.not())
toggleClass(UIAppStyle.style2, switch)
}
Snippet from UIAppStyle:
s(style1){
textFill = Color.YELLOW
maxWidth = infinity
maxHeight = infinity
alignment = Pos.CENTER
backgroundImage += this::class.java.classLoader.getResource("img.png")!!.toURI()
backgroundPosition += BackgroundPosition.CENTER
backgroundRepeat += Pair(BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT)
borderColor += box(Color.BLUE)
}
s(style2){
textFill = Color.YELLOW
maxWidth = infinity
maxHeight = infinity
alignment = Pos.CENTER
borderColor += box(Color.YELLOW)
}
When switch = false, there is a background image and a blue border. When switch = true, there is the same background image and a yellow border. I'm not finding out how to get the background image to remove. Interestingly enough, if I add a different background image to style2, it changes correctly.
Edit: To remove two toggleClasses and introduce new strange problem:
class MyView : View(){
...
init{
...
row{
repeat(myviewmodel.numSwitches){
val switch = myviewmodel.switches[it]
val notSwitch = switch.not()
label("my label"){
addClass(UIAppStyle.style2)
toggleClass(UIAppStyle.style1, notSwitch)
}
}
}
}
This code snippet does not work for me. However, if I add private var throwsArray = mutableListOf<ObservableValue<Boolean>>() as a field of MyView and add notSwitch to the array, then the same exact code works. It's almost as if notSwitch is going out of scope and becoming invalidated unless I add it to a local array in the class?
I don’t understand why you want to have two different toggleClass for the same control. As you pointed out, the problem in your case is that when the backgroundImage is set, you need to set a new one in order to change it. But in your case, you only have to add the style without backgroundImage first and them set toggleClass with the style with backgroundImage. Like this:
label("my label"){
addClass(UIAppStyle.style2)
toggleClass(UIAppStyle.style1, switch)
}
button {
action {
switch.value = !switch.value;
}
}
Edit: This ilustrate what I'm talking about in comments:
class Example : View("Example") {
override val root = vbox {
val switch = SimpleBooleanProperty(false)
val notSwitch = switch.not()
label("my label"){
addClass(UIAppStyle.style2)
toggleClass(UIAppStyle.style1, notSwitch)
}
button("One") {
action {
switch.value = !switch.value;
}
}
button("Two") {
action {
notSwitch.get()
}
}
}
}
You can put the notSwitch.get() in any action and without trigger that action it does the work. Check how I put it in the action of button Two, but without clicking that button even once, it works.
This is actually some kind of hack, in order to achieve what you want. But I don’t see the reason why my initial solution with true as default value for property shouldn’t work.
Edited to do inverse of status
Here is simple example of a working toggle class using your styling:
class TestView : View() {
override val root = vbox {
val status = SimpleBooleanProperty(false)
label("This is a label") {
addClass(UIAppStyle.base_cell)
val notStatus = SimpleBooleanProperty(!status.value)
status.onChange { notStatus.value = !it } // More consistent than a not() binding for some reason
toggleClass(UIAppStyle.smiling_cell, notStatus)
}
button("Toggle").action { status.value = !status.value }
}
init {
importStylesheet<UIAppStyle>()
}
}
As you can see, the base class is added as the default, while styling with the image is in the toggle class (no not() binding). Like mentioned in other comments, the toggleClass is picky, additive in nature, and quiet in failure so it can sometimes be confusing.
FYI I got to this only by going through your github code and I can say with confidence that the not() binding is what screwed you in regards to the toggleClass behaviour. Everything else causing an error is related to other problems with the code. Feel free to ask in the comments or post another question.

Changing cursor on a bokeh map

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.

bokeh change circle colors with select or button

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.

customize shape of kendo tooltip

I would like to customize the shape of Kendo Tooltips for a grid.
I saw the example on kendo site, it has the arrow outside the box, and the box has a nice rounded shape.
Working on css, using .k-tooltip I can change width, height, background. But I get a square box with the arrow inside which sometimes overrides part of the text content.
I thought that callout would help but I was not able to get anything.
How can I change shape, image and position of the arrows, shape of the box ?
Moreover, how can I trigger the tooltip only when part of the text in a grid cell is visible ?
Thanks a lot for any hint
regards
Marco
I think "arrow" you mean callout. You can turn off callout by:
$(document).ready(function() {
$("#target").kendoTooltip({
callout: false
});
});
About your question "Moreover, how can I trigger the tooltip only when part of the text in a grid cell is visible?"
If I understand you correctly you would like to show tooltip only when there is text with ellipsis (partially visible in the cell), but you don't want to show a tooltip if there is a full text is visible or if there is no text in the cell. If that is the case, you can do this way:
function initializeTooltip(element, filter) {
return element.kendoTooltip({
autoHide: true,
filter: filter,
callout: false,
content: function (e) {
var target = e.target,
tooltip = e.sender,
tooltipText = "";
if (isEllipsisActive(target[0])) {
tooltipText = $(target).text();
}
tooltip.popup.unbind("open");
tooltip.popup.bind("open", function (arg) {
tooltip.refreshTooltip = false;
if (!isEllipsisActive(target[0])) {
arg.preventDefault();
} else if (tooltipText !== $(target).text()) {
tooltip.refreshTooltip = true;
}
});
return tooltipText;
},
show: function () {
if (this.refreshTooltip) {
this.refresh();
}
}
}).data("kendoTooltip");
};
// determanes if text has ellipsis
function isEllipsisActive(e) {
return e.offsetWidth < e.scrollWidth;
}
$(function () {
initializeTooltip($("#yourGridId"), ".tooltip");
});
tooltip in this case is class name of the column that you would like to use tooltip for, but you can call that class anyway you wish. In case if you are using Kendo ASP.NET MVC it will look something like this
c.Bound(p => p.ClientName)
.Title("Client")
.HtmlAttributes(new {#class = "tooltip"});

cObject in Typolink assigned with border-content

Basically, I (think I ) need to know how to assign borderContent to a cObject, when it is a typolink parameter.
To tell the whole story: I'm using perfect lightbox, and I want it to open the lightbox when a text is clicked, and display the images that are in a single content element in the border section.
Looking through the manual, i found this code:
page.20 = TEXT
page.20.value = Open an image in a lightbox
page.20.typolink {
title = This is my caption
parameter.cObject = IMG_RESOURCE
parameter.cObject = fileadmin/image2.jpg
parameter.cObject.file.maxW = 600
parameter.cObject.file.maxH = 600
ATagParams = rel="lightbox[mySet]"
}
which is working fine. But I don't want the path to be hard set, but the content to be loaded from the border section, as I said. But if I try the following:
page.20 = TEXT
page.20.value = Open an image in a lightbox
page.20.typolink {
title = This is my caption
parameter.cObject = IMG_RESOURCE
parameter.cObject < styles.content.getBorder
parameter.cObject.file.maxW = 600
parameter.cObject.file.maxH = 600
ATagParams = rel="lightbox[mySet]"
}
the link is gone.
So I GUESS I'm assigning the content wrong. Somebody knows the answer?
Thanks!
(If of any help, I use automaketemplate..)
Assigning styles.content.getBorder will just assign the full content elements from the border column. This will not get you anywhere.
You will need to manually load the content elements from the border column, of course this can be done with TypoScript. It should be something like this:
page.20 = TEXT
page.20 {
value = Open an image in a lightbox
typolink {
ATagParams = rel="lightbox[mySet]"
title = This will be the title attribute
parameter.cObject = CONTENT
parameter.cObject {
table = tt_content
select {
pidInList = this
where = colPos = 3
}
renderObj = IMG_RESOURCE
renderObj.file {
import = uploads/pics
import.field = image
import.listNum = 0
width = 600
height = 600
}
}
}
}
Basically this will load all content elements on the border position from the current page. Render the first image in the list of images and return you the resource.

Resources