Боке настраиваемое действие с пользовательским значком - PullRequest
0 голосов
/ 07 июня 2019

Я пытаюсь построить некоторые пользовательские действия на графике боке внутри панели инструментов, и для этих пользовательских действий мне также нужны пользовательские значки.

Я начал с этого примера , который создает инструмент для рисования. Сработало, на этом все нормально.

Для пользовательских значков я начал с этого примера , который создает оболочку 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)))

Спасибо за вашу помощь, Габор

1 Ответ

0 голосов
/ 07 июня 2019

Или как можно указать более одного класса css для такой иконки настраиваемого действия?

В настоящее время это невозможно.Встроенный ButtonToolButtonView код делает это:

render(): void {
  empty(this.el)
  const icon = this.model.computed_icon
  if (isString(icon)) {
    if (startsWith(icon, "data:image"))
      this.el.style.backgroundImage = "url('" + icon + "')"
    else
      this.el.classList.add(icon)
  }
  this.el.title = this.model.tooltip
}

Второй кодовый путь действительно был разработан только с учетом значков встроенной панели инструментов и добавляет только один CSSучебный класс.Первый кодовый путь, который обрабатывает изображения, закодированные в виде URL-адресов данных, - это то, что мы добавили, чтобы предоставить некоторую возможность для пользовательских значков.Вот что я бы порекомендовал: закодировать значок, который вы хотите отобразить, в виде URL-адреса base64 и установить icon с этой строкой.

В качестве альтернативы вы просматриваете:

  • создание пользовательских расширений, которые подкласс ButtonTool принимают более одного класса CSS
  • делает запрос функции на GHчтобы добавить это в качестве функции

Первый - намного больше работы, а второй займет гораздо больше времени.

...