@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering
90 lines (77 loc) • 2.36 kB
text/typescript
import { type JSONObject, type KeyValue, ObjectExt } from '../../common'
import type { CellView } from '../../view'
import { markerRegistry } from '../marker'
import type { AttrDefinition, ComplexAttrs, SimpleAttrs } from './index'
function qualify(value: any) {
return typeof value === 'string' || ObjectExt.isPlainObject(value)
}
export const sourceMarker: AttrDefinition = {
qualify,
set(marker: string | JSONObject, { view, attrs }) {
return createMarker('marker-start', marker, view, attrs)
},
}
export const targetMarker: AttrDefinition = {
qualify,
set(marker: string | JSONObject, { view, attrs }) {
return createMarker('marker-end', marker, view, attrs, {
transform: 'rotate(180)',
})
},
}
export const vertexMarker: AttrDefinition = {
qualify,
set(marker: string | JSONObject, { view, attrs }) {
return createMarker('marker-mid', marker, view, attrs)
},
}
function createMarker(
type: 'marker-start' | 'marker-end' | 'marker-mid',
marker: string | JSONObject,
view: CellView,
attrs: ComplexAttrs,
manual: SimpleAttrs = {},
) {
const def = typeof marker === 'string' ? { name: marker } : marker
const { name, args, ...others } = def
let preset = others
if (name && typeof name === 'string') {
const fn = markerRegistry.get(name)
if (fn) {
preset = fn({ ...others, ...(args as KeyValue) })
} else {
return markerRegistry.onNotFound(name)
}
}
const options: any = {
...normalizeAttr(attrs, type),
...manual,
...preset,
}
return {
[type]: `url(#${view.graph.defineMarker(options)})`,
}
}
function normalizeAttr(
attr: ComplexAttrs,
type: 'marker-start' | 'marker-end' | 'marker-mid',
) {
const result: SimpleAttrs = {}
// The context 'fill' is disregared here. The usual case is to use the
// marker with a connection(for which 'fill' attribute is set to 'none').
const stroke = attr.stroke
if (typeof stroke === 'string') {
result.stroke = stroke
result.fill = stroke
}
if (type !== 'marker-mid') {
const strokeWidth = parseFloat(
(attr.strokeWidth || attr['stroke-width']) as string,
)
if (Number.isFinite(strokeWidth) && strokeWidth > 1) {
const offset = Math.ceil(strokeWidth / 2)
result.refX = type === 'marker-start' ? offset : -offset
}
}
return result
}