Skip to content

Commit

Permalink
feat: ✨ add cell-editor tool (#1202)
Browse files Browse the repository at this point in the history
  • Loading branch information
NewByVector authored and bubkoo committed Nov 10, 2021
1 parent d25ebd6 commit 02740ee
Show file tree
Hide file tree
Showing 19 changed files with 636 additions and 11 deletions.
6 changes: 0 additions & 6 deletions packages/x6/src/graph/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -648,12 +648,6 @@ export class Graph extends Basecoat<EventArgs> {
return this
}

/**
* **Deprecation Notice:** `scale` is deprecated and will be moved in next
* major release. Use `zoom()` instead.
*
* @deprecated
*/
scale(): Dom.Scale
scale(sx: number, sy?: number, cx?: number, cy?: number): this
scale(sx?: number, sy: number = sx as number, cx = 0, cy = 0) {
Expand Down
3 changes: 3 additions & 0 deletions packages/x6/src/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@
@import './addon/transform/index';
@import './addon/knob/index';
@import './graph/print';

// tools
@import './registry/tool/editor';
21 changes: 21 additions & 0 deletions packages/x6/src/registry/tool/editor.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@import '../../style/index';

.@{x6-prefix}-cell-tool-editor {
position: relative;
display: inline-block;
min-height: 1em;
margin: 0;
padding: 0;
line-height: 1;
white-space: normal;
text-align: center;
vertical-align: top;
overflow-wrap: normal;
outline: none;
transform-origin: 0 0;
-webkit-user-drag: none;
}
.@{x6-prefix}-edge-tool-editor {
border: 1px solid #275fc5;
border-radius: 2px;
}
230 changes: 230 additions & 0 deletions packages/x6/src/registry/tool/editor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import { ToolsView } from '../../view/tool'
import { Cell, Edge } from '../../model'
import { CellView, NodeView, EdgeView } from '../../view'
import { Point } from '../../geometry'
import { Dom, FunctionExt } from '../../util'

export class CellEditor extends ToolsView.ToolItem<
NodeView | EdgeView,
CellEditor.CellEditorOptions & { event: JQuery.MouseEventBase }
> {
private editor: HTMLDivElement
private labelIndex = -1
private distance = 0.5

render() {
this.createElement()
this.update()
this.autoFocus()
this.delegateDocumentEvents(this.options.documentEvents!)

return this
}

createElement() {
const { cell } = this
const classNames = [
this.prefixClassName(`${cell.isEdge() ? 'edge' : 'node'}-tool-editor`),
this.prefixClassName('cell-tool-editor'),
]
this.editor = ToolsView.createElement('div', false) as HTMLDivElement
this.addClass(classNames, this.editor)
this.editor.contentEditable = 'true'
this.container.appendChild(this.editor)
}

update() {
const { graph, cell, editor } = this
const style = editor.style

// set tool position
let pos = new Point()
let minWidth = 20
if (cell.isNode()) {
pos = cell.getBBox().center
minWidth = cell.size().width - 4
} else if (cell.isEdge()) {
const e = this.options.event
const target = e.target
const parent = target.parentElement
const isEdgeLabel =
parent && Dom.hasClass(parent, this.prefixClassName('edge-label'))
if (isEdgeLabel) {
const index = parent.getAttribute('data-index') || '0'
this.labelIndex = parseInt(index, 10)
const matrix = parent.getAttribute('transform')
const { translation } = Dom.parseTransformString(matrix)
pos = new Point(translation.tx, translation.ty)
minWidth = Dom.getBBox(target).width
} else {
pos = graph.clientToLocal(Point.create(e.clientX, e.clientY))
const view = this.cellView as EdgeView
const d = view.path.closestPointLength(pos)
this.distance = d
}
}
pos = graph.localToGraph(pos)
style.left = `${pos.x}px`
style.top = `${pos.y}px`
style.minWidth = `${minWidth}px`

// set tool transform
const scale = graph.scale()
style.transform = `scale(${scale.sx}, ${scale.sy}) translate(-50%, -50%)`

// set font style
const attrs = this.options.attrs
style.fontSize = `${attrs.fontSize}px`
style.fontFamily = attrs.fontFamily
style.color = attrs.color
style.backgroundColor = attrs.backgroundColor

// set init value
const getText = this.options.getText
let text
if (typeof getText === 'function') {
text = FunctionExt.call(getText, this.cellView, {
cell: this.cell,
index: this.labelIndex,
})
}
editor.innerText = text || ''

return this
}

onDocumentMouseDown(e: JQuery.MouseDownEvent) {
if (e.target !== this.editor) {
const cell = this.cell
const value = this.editor.innerText.replace(/\n$/, '') || ''
// set value
const setText = this.options.setText
if (typeof setText === 'function') {
FunctionExt.call(setText, this.cellView, {
cell: this.cell,
value,
index: this.labelIndex,
distance: this.distance,
})
}
// remove tool
cell.removeTool(cell.isEdge() ? 'edge-editor' : 'node-editor')
this.undelegateDocumentEvents()
}
}

onDblClick(e: JQuery.DoubleClickEvent) {
e.stopPropagation()
}

onMouseDown(e: JQuery.MouseDownEvent) {
e.stopPropagation()
}

autoFocus() {
setTimeout(() => {
this.editor.focus()
this.selectText()
})
}

selectText() {
if (window.getSelection) {
const range = document.createRange()
const selection = window.getSelection()!
range.selectNodeContents(this.editor)
selection.removeAllRanges()
selection.addRange(range)
}
}
}

export namespace CellEditor {
export interface CellEditorOptions extends ToolsView.ToolItem.Options {
attrs: {
fontSize: number
fontFamily: string
color: string
backgroundColor: string
}
getText: (
this: CellView,
args: {
cell: Cell
index?: number
},
) => string
setText: (
this: CellView,
args: {
cell: Cell
value: string
index?: number
distance?: number
},
) => void
}
}

export namespace CellEditor {
CellEditor.config({
tagName: 'div',
isSVGElement: false,
events: {
dblclick: 'onDblClick',
mousedown: 'onMouseDown',
},
documentEvents: {
mousedown: 'onDocumentMouseDown',
},
})
}

export namespace CellEditor {
export const NodeEditor = CellEditor.define<CellEditorOptions>({
attrs: {
fontSize: 14,
fontFamily: 'Arial, helvetica, sans-serif',
color: '#000',
backgroundColor: '#fff',
},
getText({ cell }) {
return cell.attr('text/text')
},
setText({ cell, value }) {
cell.attr('text/text', value)
},
})

export const EdgeEditor = CellEditor.define<CellEditorOptions>({
attrs: {
fontSize: 14,
fontFamily: 'Arial, helvetica, sans-serif',
color: '#000',
backgroundColor: '#fff',
},
getText({ cell, index }) {
if (index === -1) {
return ''
}
return cell.prop(`labels/${index}/attrs/label/text`)
},
setText({ cell, value, index, distance }) {
const edge = cell as Edge
if (index === -1) {
edge.appendLabel({
position: {
distance: distance!,
},
attrs: {
label: {
text: value,
},
},
})
} else {
edge.prop(`labels/${index}/attrs/label/text`, value)
}
},
})
}
3 changes: 3 additions & 0 deletions packages/x6/src/registry/tool/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import { Vertices } from './vertices'
import { Segments } from './segments'
import { SourceAnchor, TargetAnchor } from './anchor'
import { SourceArrowhead, TargetArrowhead } from './arrowhead'
import { CellEditor } from './editor'

export namespace NodeTool {
export const presets = {
boundary: Boundary,
button: Button,
'button-remove': Button.Remove,
'node-editor': CellEditor.NodeEditor,
}

export type Definition = ToolsView.ToolItem.Definition
Expand Down Expand Up @@ -81,6 +83,7 @@ export namespace EdgeTool {
'target-anchor': TargetAnchor,
'source-arrowhead': SourceArrowhead,
'target-arrowhead': TargetArrowhead,
'edge-editor': CellEditor.EdgeEditor,
}

export type Definition = NodeTool.Definition
Expand Down
19 changes: 19 additions & 0 deletions packages/x6/src/style/raw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1241,4 +1241,23 @@ export const content = `.x6-graph {
display: none;
}
}
.x6-cell-tool-editor {
position: relative;
display: inline-block;
min-height: 1em;
padding: 0px;
margin: 0px;
line-height: 1;
text-align: center;
outline: none;
white-space: normal;
transform-origin: 0px 0px;
overflow-wrap: normal;
vertical-align: top;
-webkit-user-drag: none;
}
.x6-edge-tool-editor {
border: 1px solid #275FC5;
border-radius: 2px;
}
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
GENERATE_SOURCEMAP=false
SKIP_PREFLIGHT_CHECK=true
PUBLIC_URL='./'
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
react-app-env.d.ts
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "@antv/x6-sites-demos-api.registry.node-tool.editor",
"version": "0.1.0",
"private": true,
"dependencies": {
"@antv/x6": "latest",
"@antv/x6-sites-demos-helper": "latest",
"antd": "^4.4.2",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "^3.4.1"
},
"devDependencies": {
"@types/react": "^16.9.19",
"@types/react-dom": "^16.9.5",
"typescript": "^4.1.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"deploy": "yarn -s prepare && yarn -s static",
"prestart": "yarn prepare"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Loading

0 comments on commit 02740ee

Please sign in to comment.