Я пытаюсь построить некоторые пользовательские действия на графике боке внутри панели инструментов, и для этих пользовательских действий мне также нужны пользовательские значки.
Я начал с этого примера , который создает инструмент для рисования. Сработало, на этом все нормально.
Для пользовательских значков я начал с этого примера , который создает оболочку bokeh над fontawesome 4.6.3. Работал как шарм.
Теперь я хотел объединить эти два, поэтому сначала я убедился, что оболочка fontawesome_icon.py импортирована. Затем значок, который будет использоваться для инструмента рисования, должен быть установлен на обернутый потрясающий значок, поэтому значок DrawTool должен стать
icon = "bk-u-fa bk-u-fa-pencil"
, потому что именно так указываются потрясающие значки.
Но эта установка генерирует следующую ошибку в браузере на стороне клиента:
Error rendering Bokeh items: DOMException: Failed to execute 'add' on 'DOMTokenList': The token provided ('bk-u-fa bk-u-fa-pencil') contains HTML space characters, which are not valid in tokens.
at e.t.render (http://localhost:5006/static/js/bokeh.min.js?v=afab3eba5b3a72c05610143940e03c8e:31:460843)
at e.render (http://localhost:5006/static/js/bokeh.min.js?v=afab3eba5b3a72c05610143940e03c8e:31:517274)
at e.t.initialize (http://localhost:5006/static/js/bokeh.min.js?v=afab3eba5b3a72c05610143940e03c8e:31:460541)
at e.t [as constructor] (http://localhost:5006/static/js/bokeh.min.js?v=afab3eba5b3a72c05610143940e03c8e:31:93458)
at e.t [as constructor] (http://localhost:5006/static/js/bokeh.min.js?v=afab3eba5b3a72c05610143940e03c8e:31:16968)
at e.t [as constructor] (http://localhost:5006/static/js/bokeh.min.js?v=afab3eba5b3a72c05610143940e03c8e:31:460274)
at new e (http://localhost:5006/static/js/bokeh.min.js?v=afab3eba5b3a72c05610143940e03c8e:31:517173)
at Object.i.build_views (http://localhost:5006/static/js/bokeh.min.js?v=afab3eba5b3a72c05610143940e03c8e:31:13738)
at t._build_tool_button_views (http://localhost:5006/static/js/bokeh.min.js?v=afab3eba5b3a72c05610143940e03c8e:31:524696)
at t.initialize (http://localhost:5006/static/js/bokeh.min.js?v=afab3eba5b3a72c05610143940e03c8e:31:523943)
Так что, очевидно, не нравится, что я дал два класса в одной строке с иконкой.
Я пробовал несколько способов указать оба класса: ["bk-u-fa", "bk-u-fa-power-off"]
, "bk-u-fa"; "bk-u-fa-power-off"
, "bk-u-fa" "bk-u-fa-power-off"
, "bk-u-fa", "bk-u-fa-power-off"
, но ни один из них не сработал.
Таким образом, вопрос в том, существует ли другой способ выполнения настраиваемого действия с настраиваемым значком?
Или как можно указать более одного класса CSS для такой иконки настраиваемого действия? Или, может быть, первый класс может быть указан в виде строки значков, а другая часть - как некоторый пользовательский класс CSS?
Ниже вы можете найти мое основное приложение под названием mygestures.py, вам просто нужно скопировать этот файл в пример и запустить его с bokeh serve --show mygestures.py
. У него есть кнопка, которая добавляет внизу текст и значок, чтобы убедиться, что значки работают.
from bokeh.core.properties import Instance
from bokeh.models import ColumnDataSource, Tool
from bokeh.util.compiler import TypeScript
from bokeh.layouts import column, row
from bokeh.plotting import figure, curdoc
from bokeh.models import Button
from bokeh.models import CustomJS
from fontawesome_icon import FontAwesomeIcon
TS_CODE = """
import {GestureTool, GestureToolView} from "models/tools/gestures/gesture_tool"
import {ColumnDataSource} from "models/sources/column_data_source"
import {GestureEvent} from "core/ui_events"
import * as p from "core/properties"
export class DrawToolView extends GestureToolView {
model: DrawTool
//this is executed when the pan/drag event starts
_pan_start(_ev: GestureEvent): void {
this.model.source.data = {x: [], y: []}
}
//this is executed on subsequent mouse/touch moves
_pan(ev: GestureEvent): void {
const {frame} = this.plot_view
const {sx, sy} = ev
if (!frame.bbox.contains(sx, sy))
return
const x = frame.xscales.default.invert(sx)
const y = frame.yscales.default.invert(sy)
const {source} = this.model
source.get_array("x").push(x)
source.get_array("y").push(y)
source.change.emit()
}
// this is executed then the pan/drag ends
_pan_end(_ev: GestureEvent): void {}
}
export namespace DrawTool {
export type Attrs = p.AttrsOf<Props>
export type Props = GestureTool.Props & {
source: p.Property<ColumnDataSource>
}
}
export interface DrawTool extends DrawTool.Attrs {}
export class DrawTool extends GestureTool {
properties: DrawTool.Props
constructor(attrs?: Partial<DrawTool.Attrs>) {
super(attrs)
}
tool_name = "Drag Span"
icon = "bk-u-fa bk-u-fa-pencil"
event_type = "pan" as "pan"
default_order = 12
static initClass(): void {
this.prototype.type = "DrawTool"
this.prototype.default_view = DrawToolView
this.define<DrawTool.Props>({
source: [ p.Instance ],
})
}
}
DrawTool.initClass()
"""
class DrawTool(Tool):
__implementation__ = TypeScript(TS_CODE)
source = Instance(ColumnDataSource)
source = ColumnDataSource(data=dict(x=[], y=[]))
plot = figure(x_range=(0, 10), y_range=(0, 10), tools=[DrawTool(source=source)])
plot.title.text = "Drag to draw on the plot"
plot.line('x', 'y', source=source)
# show(plot)
button = Button(label="Press Me", callback=CustomJS(
code="""
console.log("button callback");
btn = document.createElement("div");
btn.innerHTML = "<h1><i class=\\"bk-u-fa bk-u-fa-pencil\\"></i> Icon and some text</h1>";
document.getElementsByClassName("bk-root")[0].appendChild(btn);
"""
))
plot = figure(x_range=(0, 10), y_range=(0, 10), tools=[DrawTool(source=source)])
plot.title.text = "Drag to draw on the plot"
plot.line('x', 'y', source=source)
curdoc().add_root(column(row(button), row(plot)))
Спасибо за вашу помощь,
Габор