'新增键盘导航,即通过方向键来切换激活的节点'
This commit is contained in:
parent
39b55b0cd7
commit
41b0b21354
14
README.md
14
README.md
@ -423,6 +423,14 @@ v0.1.5+
|
|||||||
|
|
||||||
将节点移动到另一个节点的后面
|
将节点移动到另一个节点的后面
|
||||||
|
|
||||||
|
#### moveNodeToCenter(node)
|
||||||
|
|
||||||
|
v0.2.17+
|
||||||
|
|
||||||
|
移动节点到画布中心。
|
||||||
|
|
||||||
|
目前如果是存在缩放的情况下回到中心会重置缩放。
|
||||||
|
|
||||||
## keyCommand实例
|
## keyCommand实例
|
||||||
|
|
||||||
`keyCommand`实例负责快捷键的添加及触发,内置了一些快捷键,也可以自行添加。可通过`mindMap.keyCommand`获取到该实例。
|
`keyCommand`实例负责快捷键的添加及触发,内置了一些快捷键,也可以自行添加。可通过`mindMap.keyCommand`获取到该实例。
|
||||||
@ -550,6 +558,12 @@ v0.1.1+
|
|||||||
|
|
||||||
动态设置变换数据,可以通过getTransformData方法获取变换数据
|
动态设置变换数据,可以通过getTransformData方法获取变换数据
|
||||||
|
|
||||||
|
#### setScale(scale)
|
||||||
|
|
||||||
|
v0.2.17+
|
||||||
|
|
||||||
|
设置缩放
|
||||||
|
|
||||||
## MiniMap实例
|
## MiniMap实例
|
||||||
|
|
||||||
v0.2.11+
|
v0.2.11+
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import { layoutValueList } from './src/utils/constant'
|
|||||||
import { SVG } from '@svgdotjs/svg.js'
|
import { SVG } from '@svgdotjs/svg.js'
|
||||||
import xmind from './src/parse/xmind'
|
import xmind from './src/parse/xmind'
|
||||||
import { simpleDeepClone } from './src/utils'
|
import { simpleDeepClone } from './src/utils'
|
||||||
|
import KeyboardNavigation from './src/KeyboardNavigation'
|
||||||
|
|
||||||
// 默认选项配置
|
// 默认选项配置
|
||||||
const defaultOpt = {
|
const defaultOpt = {
|
||||||
@ -133,6 +134,11 @@ class MindMap {
|
|||||||
mindMap: this
|
mindMap: this
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 键盘导航类
|
||||||
|
this.keyboardNavigation = new KeyboardNavigation({
|
||||||
|
mindMap: this
|
||||||
|
})
|
||||||
|
|
||||||
// 批量执行类
|
// 批量执行类
|
||||||
this.batchExecution = new BatchExecution()
|
this.batchExecution = new BatchExecution()
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "simple-mind-map",
|
"name": "simple-mind-map",
|
||||||
"version": "0.2.16",
|
"version": "0.2.17",
|
||||||
"description": "一个简单的web在线思维导图",
|
"description": "一个简单的web在线思维导图",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -48,6 +48,7 @@ class Event extends EventEmitter {
|
|||||||
this.onMousewheel = this.onMousewheel.bind(this)
|
this.onMousewheel = this.onMousewheel.bind(this)
|
||||||
this.onContextmenu = this.onContextmenu.bind(this)
|
this.onContextmenu = this.onContextmenu.bind(this)
|
||||||
this.onSvgMousedown = this.onSvgMousedown.bind(this)
|
this.onSvgMousedown = this.onSvgMousedown.bind(this)
|
||||||
|
this.onKeyup = this.onKeyup.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,6 +70,7 @@ class Event extends EventEmitter {
|
|||||||
this.mindMap.el.addEventListener('mousewheel', this.onMousewheel)
|
this.mindMap.el.addEventListener('mousewheel', this.onMousewheel)
|
||||||
}
|
}
|
||||||
this.mindMap.svg.on('contextmenu', this.onContextmenu)
|
this.mindMap.svg.on('contextmenu', this.onContextmenu)
|
||||||
|
window.addEventListener('keyup', this.onKeyup)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,6 +86,7 @@ class Event extends EventEmitter {
|
|||||||
window.removeEventListener('mouseup', this.onMouseup)
|
window.removeEventListener('mouseup', this.onMouseup)
|
||||||
this.mindMap.el.removeEventListener('mousewheel', this.onMousewheel)
|
this.mindMap.el.removeEventListener('mousewheel', this.onMousewheel)
|
||||||
this.mindMap.svg.off('contextmenu', this.onContextmenu)
|
this.mindMap.svg.off('contextmenu', this.onContextmenu)
|
||||||
|
window.removeEventListener('keyup', this.onKeyup)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -177,6 +180,16 @@ class Event extends EventEmitter {
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
this.emit('contextmenu', e)
|
this.emit('contextmenu', e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-12-09 11:12:11
|
||||||
|
* @Desc: 按键松开事件
|
||||||
|
*/
|
||||||
|
onKeyup(e) {
|
||||||
|
this.emit('keyup', e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Event
|
export default Event
|
||||||
|
|||||||
133
simple-mind-map/src/KeyboardNavigation.js
Normal file
133
simple-mind-map/src/KeyboardNavigation.js
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import { isKey } from './utils/keyMap'
|
||||||
|
import { bfsWalk } from './utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-12-09 11:06:50
|
||||||
|
* @Desc: 键盘导航类
|
||||||
|
*/
|
||||||
|
export default class KeyboardNavigation {
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-12-09 11:07:24
|
||||||
|
* @Desc: 构造函数
|
||||||
|
*/
|
||||||
|
constructor(opt) {
|
||||||
|
this.opt = opt
|
||||||
|
this.mindMap = opt.mindMap
|
||||||
|
this.onKeyup = this.onKeyup.bind(this)
|
||||||
|
this.mindMap.on('keyup', this.onKeyup)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-12-09 14:12:27
|
||||||
|
* @Desc: 处理按键事件
|
||||||
|
*/
|
||||||
|
onKeyup(e) {
|
||||||
|
if (this.mindMap.renderer.activeNodeList.length > 0) {
|
||||||
|
;['Left', 'Up', 'Right', 'Down'].forEach(dir => {
|
||||||
|
if (isKey(e, dir)) {
|
||||||
|
this.focus(dir)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let root = this.mindMap.renderer.root
|
||||||
|
this.mindMap.renderer.moveNodeToCenter(root)
|
||||||
|
root.active()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-12-09 14:12:39
|
||||||
|
* @Desc: 聚焦到下一个节点
|
||||||
|
*/
|
||||||
|
focus(dir) {
|
||||||
|
let currentActiveNode = this.mindMap.renderer.activeNodeList[0]
|
||||||
|
let currentActiveNodeRect = this.getNodeRect(currentActiveNode)
|
||||||
|
let targetNode = null
|
||||||
|
let targetDis = Infinity
|
||||||
|
let checkNodeDis = (rect, node) => {
|
||||||
|
let dis = this.getDistance(currentActiveNodeRect, rect)
|
||||||
|
if (dis < targetDis) {
|
||||||
|
targetNode = node
|
||||||
|
targetDis = dis
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bfsWalk(this.mindMap.renderer.root, node => {
|
||||||
|
let rect = this.getNodeRect(node)
|
||||||
|
let { left, top, right, bottom } = rect
|
||||||
|
if (dir === 'Right') {
|
||||||
|
if (left >= currentActiveNodeRect.right) {
|
||||||
|
checkNodeDis(rect, node)
|
||||||
|
}
|
||||||
|
} else if (dir === 'Left') {
|
||||||
|
if (right <= currentActiveNodeRect.left) {
|
||||||
|
checkNodeDis(rect, node)
|
||||||
|
}
|
||||||
|
} else if (dir === 'Up') {
|
||||||
|
if (bottom <= currentActiveNodeRect.top) {
|
||||||
|
checkNodeDis(rect, node)
|
||||||
|
}
|
||||||
|
} else if (dir === 'Down') {
|
||||||
|
if (top >= currentActiveNodeRect.bottom) {
|
||||||
|
checkNodeDis(rect, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (targetNode) {
|
||||||
|
this.mindMap.renderer.moveNodeToCenter(targetNode)
|
||||||
|
targetNode.active()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-12-09 14:12:50
|
||||||
|
* @Desc: 获取节点的位置信息
|
||||||
|
*/
|
||||||
|
getNodeRect(node) {
|
||||||
|
let { scaleX, scaleY, translateX, translateY } =
|
||||||
|
this.mindMap.draw.transform()
|
||||||
|
let { left, top, width, height } = node
|
||||||
|
return {
|
||||||
|
right: (left + width) * scaleX + translateX,
|
||||||
|
bottom: (top + height) * scaleY + translateY,
|
||||||
|
left: left * scaleX + translateX,
|
||||||
|
top: top * scaleY + translateY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-12-09 14:13:04
|
||||||
|
* @Desc: 获取两个节点的距离
|
||||||
|
*/
|
||||||
|
getDistance(node1Rect, node2Rect) {
|
||||||
|
let center1 = this.getCenter(node1Rect)
|
||||||
|
let center2 = this.getCenter(node2Rect)
|
||||||
|
return Math.sqrt(
|
||||||
|
Math.pow(center1.x - center2.x, 2) + Math.pow(center1.y - center2.y, 2)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-12-09 14:13:11
|
||||||
|
* @Desc: 获取节点的中心点
|
||||||
|
*/
|
||||||
|
getCenter({ left, right, top, bottom }) {
|
||||||
|
return {
|
||||||
|
x: (left + right) / 2,
|
||||||
|
y: (top + bottom) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1097,6 +1097,28 @@ class Render {
|
|||||||
this.mindMap.render()
|
this.mindMap.render()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-12-09 11:46:57
|
||||||
|
* @Desc: 移动节点到画布中心
|
||||||
|
*/
|
||||||
|
moveNodeToCenter(node) {
|
||||||
|
let halfWidth = this.mindMap.width / 2
|
||||||
|
let halfHeight = this.mindMap.height / 2
|
||||||
|
let { left, top, width, height } = node
|
||||||
|
let nodeCenterX = left + width / 2
|
||||||
|
let nodeCenterY = top + height / 2
|
||||||
|
let { state } = this.mindMap.view.getTransformData()
|
||||||
|
let targetX = halfWidth - state.x
|
||||||
|
let targetY = halfHeight - state.y
|
||||||
|
let offsetX = targetX - nodeCenterX
|
||||||
|
let offsetY = targetY - nodeCenterY
|
||||||
|
this.mindMap.view.translateX(offsetX)
|
||||||
|
this.mindMap.view.translateY(offsetY)
|
||||||
|
this.mindMap.view.setScale(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Render
|
export default Render
|
||||||
|
|||||||
@ -88,6 +88,9 @@ export default class TextEdit {
|
|||||||
this.textEditNode = document.createElement('div')
|
this.textEditNode = document.createElement('div')
|
||||||
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: 3px 5px;margin-left: -5px;margin-top: -3px;outline: none;`
|
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: 3px 5px;margin-left: -5px;margin-top: -3px;outline: none;`
|
||||||
this.textEditNode.setAttribute('contenteditable', true)
|
this.textEditNode.setAttribute('contenteditable', true)
|
||||||
|
this.textEditNode.addEventListener('keyup', e => {
|
||||||
|
e.stopPropagation()
|
||||||
|
})
|
||||||
document.body.appendChild(this.textEditNode)
|
document.body.appendChild(this.textEditNode)
|
||||||
}
|
}
|
||||||
node.style.domText(this.textEditNode, this.mindMap.view.scale)
|
node.style.domText(this.textEditNode, this.mindMap.view.scale)
|
||||||
|
|||||||
@ -213,6 +213,18 @@ class View {
|
|||||||
this.transform()
|
this.transform()
|
||||||
this.mindMap.emit('scale', this.scale)
|
this.mindMap.emit('scale', this.scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-12-09 16:31:59
|
||||||
|
* @Desc: 设置缩放
|
||||||
|
*/
|
||||||
|
setScale(scale) {
|
||||||
|
this.scale = scale
|
||||||
|
this.transform()
|
||||||
|
this.mindMap.emit('scale', this.scale)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default View
|
export default View
|
||||||
|
|||||||
@ -11,11 +11,12 @@
|
|||||||
v-model="link"
|
v-model="link"
|
||||||
size="mini"
|
size="mini"
|
||||||
placeholder="http://xxxx.com/"
|
placeholder="http://xxxx.com/"
|
||||||
|
@keyup.native.stop
|
||||||
></el-input>
|
></el-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<span class="name">{{ $t('nodeHyperlink.name') }}</span>
|
<span class="name">{{ $t('nodeHyperlink.name') }}</span>
|
||||||
<el-input v-model="linkTitle" size="mini"></el-input>
|
<el-input v-model="linkTitle" size="mini" @keyup.native.stop></el-input>
|
||||||
</div>
|
</div>
|
||||||
<span slot="footer" class="dialog-footer">
|
<span slot="footer" class="dialog-footer">
|
||||||
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
v-model="note"
|
v-model="note"
|
||||||
>
|
>
|
||||||
</el-input> -->
|
</el-input> -->
|
||||||
<div class="noteEditor" ref="noteEditor"></div>
|
<div class="noteEditor" ref="noteEditor" @keyup.stop></div>
|
||||||
<!-- <div class="tip">换行请使用:Enter+Shift</div> -->
|
<!-- <div class="tip">换行请使用:Enter+Shift</div> -->
|
||||||
<span slot="footer" class="dialog-footer">
|
<span slot="footer" class="dialog-footer">
|
||||||
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
<el-input
|
<el-input
|
||||||
v-model="tag"
|
v-model="tag"
|
||||||
@keyup.native.enter="add"
|
@keyup.native.enter="add"
|
||||||
|
@keyup.native.stop
|
||||||
:disabled="tagArr.length >= max"
|
:disabled="tagArr.length >= max"
|
||||||
:placeholder="$t('nodeTag.addTip')"
|
:placeholder="$t('nodeTag.addTip')"
|
||||||
>
|
>
|
||||||
|
|||||||
@ -8,7 +8,15 @@
|
|||||||
default-expand-all
|
default-expand-all
|
||||||
>
|
>
|
||||||
<span class="customNode" slot-scope="{ node, data }">
|
<span class="customNode" slot-scope="{ node, data }">
|
||||||
<span class="nodeEdit" :key="getKey()" contenteditable="true" @keydown.stop @keyup.stop @blur="onBlur($event, node)" v-html="node.label"></span>
|
<span
|
||||||
|
class="nodeEdit"
|
||||||
|
:key="getKey()"
|
||||||
|
contenteditable="true"
|
||||||
|
@keydown.stop
|
||||||
|
@keyup.stop
|
||||||
|
@blur="onBlur($event, node)"
|
||||||
|
v-html="node.label"
|
||||||
|
></span>
|
||||||
</span>
|
</span>
|
||||||
</el-tree>
|
</el-tree>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user