@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering
138 lines (111 loc) • 3.56 kB
text/typescript
import { Dom, ObjectExt, Util, Vector } from '../../common'
import { Config } from '../../config'
import type { EdgeView } from '../../view'
import type { SimpleAttrs } from '../attr'
import type { HighlighterDefinition } from './index'
export interface StrokeHighlighterOptions {
padding?: number
rx?: number
ry?: number
attrs?: SimpleAttrs
}
const defaultOptions: StrokeHighlighterOptions = {
padding: 3,
rx: 0,
ry: 0,
attrs: {
'stroke-width': 3,
stroke: '#FEB663',
},
}
export const stroke: HighlighterDefinition<StrokeHighlighterOptions> = {
highlight(cellView, magnet, options) {
const id = getHighlighterId(magnet, options)
if (hasCache(id)) {
return
}
// eslint-disable-next-line
options = ObjectExt.defaultsDeep({}, options, defaultOptions)
const magnetVel = Vector.create(magnet as SVGElement)
let pathData
let magnetBBox
try {
pathData = magnetVel.toPathData()
} catch (error) {
// Failed to get path data from magnet element.
// Draw a rectangle around the entire cell view instead.
magnetBBox = Util.bbox(magnetVel.node, true)
pathData = Dom.rectToPathData({ ...options, ...magnetBBox })
}
const path = Dom.createSvgElement('path')
Dom.attr(path, {
d: pathData,
'pointer-events': 'none',
'vector-effect': 'non-scaling-stroke',
fill: 'none',
...(options.attrs ? Dom.kebablizeAttrs(options.attrs) : null),
})
// const highlightVel = v.create('path').attr()
if (cellView.isEdgeElement(magnet)) {
Dom.attr(path, 'd', (cellView as EdgeView).getConnectionPathData())
} else {
let highlightMatrix = magnetVel.getTransformToElement(
cellView.container as SVGElement,
)
// Add padding to the highlight element.
const padding = options.padding
if (padding) {
if (magnetBBox == null) {
magnetBBox = Util.bbox(magnetVel.node, true)
}
const cx = magnetBBox.x + magnetBBox.width / 2
const cy = magnetBBox.y + magnetBBox.height / 2
magnetBBox = Util.transformRectangle(magnetBBox, highlightMatrix)
const width = Math.max(magnetBBox.width, 1)
const height = Math.max(magnetBBox.height, 1)
const sx = (width + padding) / width
const sy = (height + padding) / height
const paddingMatrix = Dom.createSVGMatrix({
a: sx,
b: 0,
c: 0,
d: sy,
e: cx - sx * cx,
f: cy - sy * cy,
})
highlightMatrix = highlightMatrix.multiply(paddingMatrix)
}
Dom.transform(path, highlightMatrix)
}
Dom.addClass(path, Config.prefix('highlight-stroke'))
const cell = cellView.cell
const removeHandler = () => removeHighlighter(id)
cell.on('removed', removeHandler)
if (cell.model) {
cell.model.on('reseted', removeHandler)
}
cellView.container.appendChild(path)
setCache(id, path)
},
unhighlight(cellView, magnet, opt) {
removeHighlighter(getHighlighterId(magnet, opt))
},
}
function getHighlighterId(magnet: Element, options: StrokeHighlighterOptions) {
Dom.ensureId(magnet)
return magnet.id + JSON.stringify(options)
}
const cache: { [id: string]: Element } = {}
function setCache(id: string, elem: Element) {
cache[id] = elem
}
function hasCache(id: string) {
return cache[id] != null
}
function removeHighlighter(id: string) {
const elem = cache[id]
if (elem) {
Dom.remove(elem)
delete cache[id]
}
}