import type { RuntimeContext } from '../../runtime/types'; import type { CornerPlacement } from '../../types'; import type { BasePluginOptions } from '../base-plugin'; import { BasePlugin } from '../base-plugin'; import { createPluginContainer, insertDOM } from '../utils/dom'; import type { ToolbarItem } from './util'; import { BUILD_IN_SVG_ICON, TOOLBAR_CSS, parsePositionToStyle } from './util'; /** * Toolbar 工具栏的配置项 * * The options of the Toolbar toolbar */ export interface ToolbarOptions extends BasePluginOptions { /** * 给工具栏的 DOM 追加的 classname,便于自定义样式。默认是包含 `g6-toolbar` * * The classname appended to the menu DOM for custom styles. The default is `g6-toolbar` */ className?: string; /** * Toolbar 的位置,相对于画布,会影响 DOM 的 style 样式 * * The position of the Toolbar relative to the canvas, which will affect the style of the DOM * @defaultValue 'top-left' */ position?: CornerPlacement; /** * 工具栏显式的 style 样式,可以用来设置它相对于画布的位置、背景容器样式等 * * The style style of the Toolbar, which can be used to set its position relative to the canvas */ style?: Partial; /** * 当工具栏被点击后,触发的回调方法 * * The callback method triggered when the toolbar item is clicked */ onClick?: (value: string, target: Element) => void; /** * 返回工具栏的项目列表,支持 `Promise` 类型的返回值 * * Return the list of toolbar items, support return a `Promise` as items */ getItems: () => ToolbarItem[] | Promise; } /** * 工具栏,支持配置工具栏项目,以及点击之后的回调方法 * * Toolbar, support configuration of toolbar items, and callback methods after clicking */ export class Toolbar extends BasePlugin { static defaultOptions: Partial = { position: 'top-left', }; private $element: HTMLElement = createPluginContainer('toolbar', false); constructor(context: RuntimeContext, options: ToolbarOptions) { super(context, Object.assign({}, Toolbar.defaultOptions, options)); const $container = this.context.canvas.getContainer(); this.$element.style.display = 'flex'; $container!.appendChild(this.$element); // 设置样式 insertDOM('g6-toolbar-css', 'style', {}, TOOLBAR_CSS, document.head); insertDOM('g6-toolbar-svgicon', 'div', { display: 'none' }, BUILD_IN_SVG_ICON); this.$element.addEventListener('click', this.onToolbarItemClick); this.update(options); } /** * 更新工具栏的配置项 * * Update the configuration of the toolbar * @param options - 工具栏的配置项 | The options of the toolbar * @internal */ public async update(options: Partial) { super.update(options); const { className, position, style } = this.options; this.$element.className = `g6-toolbar ${className || ''}`; // 设置容器的样式,主要是位置,背景之类的 Object.assign(this.$element.style, style, parsePositionToStyle(position)); this.$element.innerHTML = await this.getDOMContent(); } /** * 销毁工具栏 * * Destroy the toolbar * @internal */ public destroy(): void { this.$element.removeEventListener('click', this.onToolbarItemClick); this.$element.remove(); super.destroy(); } private async getDOMContent() { const items = await this.options.getItems(); return items .map( (item) => `
`, ) .join(''); } private onToolbarItemClick = (e: MouseEvent) => { const { onClick } = this.options; if (e.target instanceof Element) { if (e.target.className.includes('g6-toolbar-item')) { const v = e.target.getAttribute('value') as string; onClick?.(v, e.target); } } }; }