@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering.
197 lines (171 loc) • 4.47 kB
text/typescript
import { Point } from '../../geometry'
import { Dom, NumberExt, FunctionExt } from '../../util'
import { CellView } from '../../view/cell'
import { NodeView } from '../../view/node'
import { EdgeView } from '../../view/edge'
import { ToolsView } from '../../view/tool'
import * as Util from './util'
import { Cell } from '../../model'
export class Button extends ToolsView.ToolItem<
EdgeView | NodeView,
Button.Options
> {
protected onRender() {
Dom.addClass(this.container, this.prefixClassName('cell-tool-button'))
this.update()
}
update() {
this.updatePosition()
return this
}
protected updatePosition() {
const view = this.cellView
const matrix = view.cell.isEdge()
? this.getEdgeMatrix()
: this.getNodeMatrix()
Dom.transform(this.container as SVGElement, matrix, { absolute: true })
}
protected getNodeMatrix() {
const view = this.cellView as NodeView
const options = this.options
let { x = 0, y = 0 } = options
const { offset, useCellGeometry, rotate } = options
let bbox = Util.getViewBBox(view, useCellGeometry)
const angle = view.cell.getAngle()
if (!rotate) {
bbox = bbox.bbox(angle)
}
let offsetX = 0
let offsetY = 0
if (typeof offset === 'number') {
offsetX = offset
offsetY = offset
} else if (typeof offset === 'object') {
offsetX = offset.x
offsetY = offset.y
}
x = NumberExt.normalizePercentage(x, bbox.width)
y = NumberExt.normalizePercentage(y, bbox.height)
let matrix = Dom.createSVGMatrix().translate(
bbox.x + bbox.width / 2,
bbox.y + bbox.height / 2,
)
if (rotate) {
matrix = matrix.rotate(angle)
}
matrix = matrix.translate(
x + offsetX - bbox.width / 2,
y + offsetY - bbox.height / 2,
)
return matrix
}
protected getEdgeMatrix() {
const view = this.cellView as EdgeView
const options = this.options
const { offset = 0, distance = 0, rotate } = options
let tangent
let position
let angle
if (NumberExt.isPercentage(distance)) {
tangent = view.getTangentAtRatio(parseFloat(distance) / 100)
} else {
tangent = view.getTangentAtLength(distance)
}
if (tangent) {
position = tangent.start
angle = tangent.vector().vectorAngle(new Point(1, 0)) || 0
} else {
position = view.getConnection()!.start!
angle = 0
}
let matrix = Dom.createSVGMatrix()
.translate(position.x, position.y)
.rotate(angle)
if (typeof offset === 'object') {
matrix = matrix.translate(offset.x || 0, offset.y || 0)
} else {
matrix = matrix.translate(0, offset)
}
if (!rotate) {
matrix = matrix.rotate(-angle)
}
return matrix
}
protected onMouseDown(e: JQuery.MouseDownEvent) {
if (this.guard(e)) {
return
}
e.stopPropagation()
e.preventDefault()
const onClick = this.options.onClick
if (typeof onClick === 'function') {
FunctionExt.call(onClick, this.cellView, {
e,
view: this.cellView,
cell: this.cellView.cell,
btn: this,
})
}
}
}
export namespace Button {
export interface Options extends ToolsView.ToolItem.Options {
x?: number
y?: number
distance?: number
offset?: number | Point.PointLike
rotate?: boolean
useCellGeometry?: boolean
onClick?: (
this: CellView,
args: {
e: JQuery.MouseDownEvent
cell: Cell
view: CellView
btn: Button
},
) => any
}
}
export namespace Button {
Button.config<Button.Options>({
name: 'button',
events: {
mousedown: 'onMouseDown',
touchstart: 'onMouseDown',
},
})
}
export namespace Button {
export const Remove = Button.define<Button.Options>({
name: 'button-remove',
markup: [
{
tagName: 'circle',
selector: 'button',
attrs: {
r: 7,
fill: '#FF1D00',
cursor: 'pointer',
},
},
{
tagName: 'path',
selector: 'icon',
attrs: {
d: 'M -3 -3 3 3 M -3 3 3 -3',
fill: 'none',
stroke: '#FFFFFF',
'stroke-width': 2,
'pointer-events': 'none',
},
},
],
distance: 60,
offset: 0,
onClick({ view, btn }) {
btn.parent.remove()
view.cell.remove({ ui: true, toolId: btn.cid })
},
})
}