UNPKG

@antv/x6

Version:

JavaScript diagramming library that uses SVG and HTML for rendering.

216 lines (193 loc) 5.23 kB
import { Platform, StringExt, ObjectExt, Dom } from '../../util' import { Size } from '../../types' import { Attr } from '../../registry' import { Node } from '../../model' import { Store } from '../../model/store' import { NodeView } from '../../view' import { getName } from './util' const contentSelector = '.text-block-content' const registryName = getName('text-block') export class TextBlock< Properties extends TextBlock.Properties = TextBlock.Properties, > extends Node<Properties> { public readonly store: Store<TextBlock.Properties> get content() { return this.getContent() } set content(val: string) { this.setContent(val) } getContent() { return this.store.get('content', '') } setContent(content?: string, options: Node.SetOptions = {}) { this.store.set('content', content, options) } protected setup() { super.setup() this.store.on('change:*', (metadata) => { const key = metadata.key if (key === 'content') { this.updateContent(this.getContent()) } else if (key === 'size') { this.updateSize(this.getSize()) } }) this.updateSize(this.getSize()) this.updateContent(this.getContent()) } protected updateSize(size: Size) { if (Platform.SUPPORT_FOREIGNOBJECT) { this.setAttrs({ foreignObject: { ...size }, [contentSelector]: { style: { ...size }, }, }) } } protected updateContent(content?: string) { if (Platform.SUPPORT_FOREIGNOBJECT) { this.setAttrs({ [contentSelector]: { html: content ? StringExt.sanitizeHTML(content) : '', }, }) } else { this.setAttrs({ [contentSelector]: { text: content, }, }) } } } export namespace TextBlock { export interface Properties extends Node.Properties { content?: string } } export namespace TextBlock { TextBlock.config({ type: registryName, view: registryName, markup: [ '<g class="rotatable">', '<g class="scalable"><rect/></g>', Platform.SUPPORT_FOREIGNOBJECT ? [ `<foreignObject>`, `<body xmlns="http://www.w3.org/1999/xhtml">`, `<div class="${contentSelector.substr(1)}" />`, `</body>`, `</foreignObject>`, ].join('') : `<text class="${contentSelector.substr(1)}"/>`, '</g>', ].join(''), attrs: { '.': { fill: '#ffffff', stroke: 'none', }, rect: { fill: '#ffffff', stroke: '#000000', width: 80, height: 100, }, text: { fill: '#000000', fontSize: 14, fontFamily: 'Arial, helvetica, sans-serif', }, body: { style: { background: 'transparent', position: 'static', margin: 0, padding: 0, }, }, foreignObject: { style: { overflow: 'hidden', }, }, [contentSelector]: { refX: 0.5, refY: 0.5, yAlign: 'middle', xAlign: 'middle', style: { textAlign: 'center', verticalAlign: 'middle', display: 'table-cell', padding: '0 5px', margin: 0, }, }, }, }) Node.registry.register(registryName, TextBlock) } export namespace TextBlock { const contentAction = 'content' as any export class View extends NodeView<TextBlock> { confirmUpdate(flag: number, options: any = {}) { let ret = super.confirmUpdate(flag, options) if (this.hasAction(ret, contentAction)) { this.updateContent() ret = this.removeAction(ret, contentAction) } return ret } update(partialAttrs?: Attr.CellAttrs) { if (Platform.SUPPORT_FOREIGNOBJECT) { super.update(partialAttrs) } else { const node = this.cell const attrs = { ...(partialAttrs || node.getAttrs()) } delete attrs[contentSelector] super.update(attrs) if (!partialAttrs || ObjectExt.has(partialAttrs, contentSelector)) { this.updateContent(partialAttrs) } } } updateContent(partialAttrs?: Attr.CellAttrs) { if (Platform.SUPPORT_FOREIGNOBJECT) { super.update(partialAttrs) } else { const node = this.cell const textAttrs = (partialAttrs || node.getAttrs())[contentSelector] // Break the text to fit the node size taking into // account the attributes set on the node. const text = Dom.breakText( node.getContent(), node.getSize(), textAttrs, { svgDocument: this.graph.view.svg, }, ) const attrs = { [contentSelector]: ObjectExt.merge({}, textAttrs, { text }), } super.update(attrs) } } } export namespace View { View.config({ bootstrap: ['render', contentAction], actions: Platform.SUPPORT_FOREIGNOBJECT ? {} : { size: contentAction, content: contentAction, }, }) NodeView.registry.register(registryName, View) } }