Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
K
kityminder-core
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
吴志俊
kityminder-core
Commits
0a07428c
Commit
0a07428c
authored
Feb 18, 2014
by
techird
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refract
parent
af572c11
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
237 additions
and
140 deletions
+237
-140
dragtree.js
src/module/dragtree.js
+233
-139
layout.default.js
src/module/layout.default.js
+4
-1
No files found.
src/module/dragtree.js
View file @
0a07428c
var
GM
=
KityMinder
.
Geometry
;
// 矩形的变形动画定义
var
AreaAnimator
=
kity
.
createClass
(
"AreaAnimator"
,
{
base
:
kity
.
Animator
,
constructor
:
function
(
startArea
,
endArea
)
{
...
...
@@ -13,179 +14,272 @@ var AreaAnimator = kity.createClass( "AreaAnimator", {
}
}
);
var
MoveToParentCommand
=
kity
.
createClass
(
'MoveToParentCommand'
,
{
base
:
Command
,
execute
:
function
(
minder
,
nodes
,
parent
)
{
var
node
;
for
(
var
i
=
nodes
.
length
-
1
;
i
>=
0
;
i
--
)
{
node
=
nodes
[
i
];
if
(
node
.
getParent
()
)
{
node
.
getParent
().
removeChild
(
node
);
parent
.
appendChild
(
node
);
}
}
minder
.
initStyle
(
minder
.
getRoot
()
);
minder
.
select
(
nodes
,
true
);
}
}
);
function
boxMapper
(
node
)
{
return
node
.
getRenderContainer
().
getRenderBox
();
}
// 对拖动对象的一个替代盒子,控制整个拖放的逻辑,包括:
// 1. 从节点列表计算出拖动部分
// 2. 产生替代矩形包围拖动部分
// 3. 动画收缩替代矩形到固定大小,成为替代盒子
// 4. 控制替代盒子的移动
// 5. 计算可以 drop 的节点,产生 drop 交互提示
var
DragBox
=
kity
.
createClass
(
"DragBox"
,
{
base
:
kity
.
Group
,
constructor
:
function
(
shapeArray
,
focusPoint
)
{
constructor
:
function
(
minder
)
{
this
.
callBase
();
this
.
_targetCount
=
shapeArray
.
length
;
this
.
_focusPoint
=
focusPoint
;
this
.
_targetArea
=
this
.
_calcStartArea
(
shapeArray
);
this
.
_dragArea
=
this
.
_calcDragArea
(
focusPoint
);
this
.
_minder
=
minder
;
this
.
_draw
();
},
_calcStartArea
:
function
(
shapeArray
)
{
var
area
=
shapeArray
.
pop
().
getRenderBox
();
while
(
shapeArray
.
length
)
{
area
=
GM
.
mergeBox
(
area
,
shapeArray
.
pop
().
getRenderBox
()
);
}
return
{
x
:
area
.
left
,
y
:
area
.
top
,
width
:
area
.
width
,
height
:
area
.
height
};
},
_calcDragArea
:
function
(
focusPoint
)
{
var
width
=
80
,
height
=
30
;
return
{
x
:
focusPoint
.
x
-
width
/
2
,
y
:
focusPoint
.
y
-
height
/
2
,
width
:
width
,
height
:
height
};
},
_draw
:
function
(
container
)
{
var
d
=
this
.
_dragArea
;
this
.
_rect
=
new
kity
.
Rect
().
fill
(
'white'
).
stroke
(
'#3399ff'
,
1
);
this
.
addShape
(
this
.
_rect
.
setRadius
(
5
)
);
this
.
addShape
(
new
kity
.
Text
(
this
.
_targetCount
+
' item'
)
.
setPosition
(
this
.
_focusPoint
.
x
,
this
.
_focusPoint
.
y
+
5
)
// 绘制显示拖放范围的矩形和显示拖放信息的文本
_draw
:
function
()
{
this
.
_rect
=
new
kity
.
Rect
()
.
setRadius
(
5
)
.
fill
(
'white'
)
.
stroke
(
'#3399ff'
,
1
);
this
.
_text
=
new
kity
.
Text
()
.
setSize
(
14
)
.
setTextAnchor
(
'middle'
)
.
fill
(
'black'
)
.
setStyle
(
'cursor'
,
'default'
)
);
},
shrink
:
function
()
{
var
animator
=
new
AreaAnimator
(
this
.
_targetArea
,
this
.
_dragArea
);
animator
.
start
(
this
.
_rect
,
400
,
'easeOutQuint'
);
.
setStyle
(
'cursor'
,
'default'
);
this
.
addShapes
(
[
this
.
_rect
,
this
.
_text
]
);
},
green
:
function
()
{
this
.
_rect
.
stroke
(
'green'
,
2
).
setOpacity
(
1
);
// 从选中的节点计算拖放源
// 并不是所有选中的节点都作为拖放源,如果选中节点中存在 A 和 B,
// 并且 A 是 B 的祖先,则 B 不作为拖放源
//
// 计算过程:
// 1. 将节点按照树高排序,排序后只可能是前面节点是后面节点的祖先
// 2. 从后往前枚举排序的结果,如果发现枚举目标之前存在其祖先,
// 则排除枚举目标作为拖放源,否则加入拖放源
_calcDragSources
:
function
()
{
var
nodes
=
this
.
_minder
.
getSelectedNodes
().
slice
(
0
),
ancestors
=
[],
judge
;
// 判断 nodes 列表中是否存在 judge 的祖先
function
hasAncestor
(
nodes
,
judge
)
{
for
(
var
i
=
nodes
.
length
-
1
;
i
>=
0
;
--
i
)
{
if
(
nodes
[
i
].
isAncestorOf
(
judge
)
)
return
true
;
}
return
false
;
}
// 按照拓扑排序
nodes
.
sort
(
function
(
node1
,
node2
)
{
return
node1
.
getLevel
()
-
node2
.
getLevel
();
}
);
// 因为是拓扑有序的,所以只需往上查找
while
(
(
judge
=
nodes
.
pop
()
)
)
{
if
(
!
hasAncestor
(
nodes
,
judge
)
)
{
ancestors
.
push
(
judge
);
}
}
this
.
_dragSources
=
ancestors
;
},
blue
:
function
()
{
this
.
_rect
.
stroke
(
'#3399ff'
,
1
).
setOpacity
(
0.8
);
}
}
);
function
findAllAncestor
(
nodes
)
{
var
ancestors
=
[],
judge
;
// 计算拖放目标可以释放的节点列表(释放意味着成为其子树),存在这条限制规则:
// - 不能拖放到拖放目标的子树上(允许拖放到自身,因为多选的情况下可以把其它节点加入)
//
// 1. 加入当前节点(初始为根节点)到允许列表
// 2. 对于当前节点的每一个子节点:
// (1) 如果是拖放目标的其中一个节点,忽略(整棵子树被剪枝)
// (2) 如果不是拖放目标之一,以当前子节点为当前节点,回到 1 计算
// 3. 返回允许列表
//
_calcDropTargets
:
function
()
{
function
hasAncestor
(
nodes
,
judge
)
{
for
(
var
i
=
nodes
.
length
-
1
;
i
>=
0
;
--
i
)
{
if
(
nodes
[
i
].
isAncestorOf
(
judge
)
)
return
true
;
function
findAvailableParents
(
nodes
,
root
)
{
var
availables
=
[],
i
;
availables
.
push
(
root
);
root
.
getChildren
().
forEach
(
function
(
test
)
{
for
(
i
=
0
;
i
<
nodes
.
length
;
i
++
)
{
if
(
nodes
[
i
]
==
test
)
return
;
}
availables
=
availables
.
concat
(
findAvailableParents
(
nodes
,
test
)
);
}
);
return
availables
;
}
return
false
;
}
nodes
.
sort
(
function
(
node1
,
node2
)
{
return
node1
.
getLevel
()
-
node2
.
getLevel
(
);
}
);
this
.
_dropTargets
=
findAvailableParents
(
this
.
_dragSources
,
this
.
_minder
.
getRoot
()
);
this
.
_dropTargetBoxes
=
this
.
_dropTargets
.
map
(
boxMapper
);
}
,
while
(
(
judge
=
nodes
.
pop
()
)
)
{
if
(
!
hasAncestor
(
nodes
,
judge
)
)
{
ancestors
.
push
(
judge
);
// 进入拖放模式:
// 1. 计算拖放源和允许的拖放目标
// 2. 渲染拖放盒子
// 3. 启动收缩动画
// 4. 标记已启动
_enterDragMode
:
function
()
{
this
.
_calcDragSources
();
this
.
_calcDropTargets
();
this
.
_drawForDragMode
();
this
.
_shrink
();
this
.
_dragMode
=
true
;
},
_leaveDragMode
:
function
()
{
this
.
remove
();
this
.
_dragMode
=
false
;
this
.
_dropSucceedTarget
=
null
;
},
_drawForDragMode
:
function
()
{
this
.
_text
.
setContent
(
this
.
_dragSources
.
length
+
' items'
);
this
.
_text
.
setPosition
(
this
.
_startPosition
.
x
,
this
.
_startPosition
.
y
+
5
);
this
.
_minder
.
getRenderContainer
().
addShape
(
this
);
},
_shrink
:
function
()
{
// 合并所有拖放源图形的矩形即可
function
calcSourceArea
(
boxArray
)
{
var
area
=
boxArray
.
pop
();
while
(
boxArray
.
length
)
{
area
=
GM
.
mergeBox
(
area
,
boxArray
.
pop
()
);
}
return
{
x
:
area
.
left
,
y
:
area
.
top
,
width
:
area
.
width
,
height
:
area
.
height
};
}
// 从焦点发散出一个固定的矩形即可
function
calcFocusArea
(
focusPoint
)
{
var
width
=
80
,
height
=
30
;
return
{
x
:
focusPoint
.
x
-
width
/
2
,
y
:
focusPoint
.
y
-
height
/
2
,
width
:
width
,
height
:
height
};
}
}
return
ancestors
;
}
function
findAvailableParents
(
nodes
,
root
)
{
var
availables
=
[],
i
;
availables
.
push
(
root
);
root
.
getChildren
().
forEach
(
function
(
test
)
{
for
(
i
=
0
;
i
<
nodes
.
length
;
i
++
)
{
if
(
nodes
[
i
]
==
test
)
return
;
var
sourceArea
=
calcSourceArea
(
this
.
_dragSources
.
map
(
boxMapper
)
);
var
focusArea
=
calcFocusArea
(
this
.
_startPosition
);
var
animator
=
new
AreaAnimator
(
sourceArea
,
focusArea
);
animator
.
start
(
this
.
_rect
,
400
,
'easeOutQuint'
);
},
// 此处可用线段树优化,但考虑到节点不多,必要性不到,就用暴力测试
_dropTest
:
function
()
{
var
dragBox
=
this
.
getRenderBox
(),
test
;
this
.
_dropSucceedTarget
=
null
;
for
(
var
i
=
0
;
i
<
this
.
_dropTargetBoxes
.
length
;
i
++
)
{
test
=
this
.
_dropTargetBoxes
[
i
];
if
(
GM
.
isBoxIntersect
(
dragBox
,
test
)
)
{
this
.
_dropSucceedTarget
=
this
.
_dropTargets
[
i
];
return
;
}
}
},
_updateDropHint
:
function
()
{
var
target
=
this
.
_dropSucceedTarget
,
lastTarget
=
this
.
_lastSucceedTarget
;
if
(
target
&&
target
==
lastTarget
)
return
;
if
(
lastTarget
)
{
this
.
_removeDropStyle
(
lastTarget
);
}
if
(
target
)
{
this
.
_addDropStyle
(
target
);
this
.
_lastSucceedTarget
=
target
;
}
},
_removeDropStyle
:
function
(
node
)
{
node
.
_layout
.
bgRect
.
stroke
(
'none'
);
},
_addDropStyle
:
function
(
node
)
{
node
.
_layout
.
bgRect
.
stroke
(
'rgb(254, 219, 0)'
,
2
);
},
dragStart
:
function
(
position
)
{
// 只记录开始位置,不马上开启拖放模式
// 这个位置同时是拖放范围收缩时的焦点位置(中心)
this
.
_startPosition
=
position
;
},
dragMove
:
function
(
position
)
{
if
(
!
this
.
_startPosition
)
return
;
this
.
_dragPosition
=
position
;
if
(
!
this
.
_dragMode
)
{
// 判断拖放模式是否该启动
if
(
GM
.
getDistance
(
this
.
_dragPosition
,
this
.
_startPosition
)
<
10
)
{
return
;
}
this
.
_enterDragMode
();
}
availables
=
availables
.
concat
(
findAvailableParents
(
nodes
,
test
)
);
}
);
return
availables
;
}
var
lastActivedDropTarget
=
null
;
function
activeDropTarget
(
node
)
{
if
(
lastActivedDropTarget
!=
node
)
{
node
.
getRenderContainer
().
fxScale
(
1.6
,
1.6
,
200
,
'ease'
).
fxScale
(
1
/
1.6
,
1
/
1.6
,
300
,
'ease'
);
lastActivedDropTarget
=
node
;
var
movement
=
kity
.
Vector
.
fromPoints
(
this
.
_startPosition
,
this
.
_dragPosition
);
this
.
setTransform
(
new
kity
.
Matrix
().
translate
(
movement
.
x
,
movement
.
y
)
);
this
.
_dropTest
();
this
.
_updateDropHint
();
},
dragEnd
:
function
()
{
this
.
_startPosition
=
null
;
if
(
!
this
.
_dragMode
)
{
return
;
}
if
(
this
.
_dropSucceedTarget
)
{
this
.
_minder
.
execCommand
(
'movetoparent'
,
this
.
_dragSources
,
this
.
_dropSucceedTarget
);
}
this
.
_leaveDragMode
();
}
}
}
);
KityMinder
.
registerModule
(
"DragTree"
,
function
()
{
var
dragStartPosition
,
dragBox
,
dragTargets
,
dropTargets
,
dragTargetBoxes
,
dropTarget
;
return
{
init
:
function
()
{
this
.
_dragBox
=
new
DragBox
(
this
);
},
events
:
{
mousedown
:
function
(
e
)
{
var
clickNode
=
e
.
getTargetNode
();
if
(
!
clickNode
)
{
return
;
if
(
e
.
getTargetNode
()
)
{
this
.
_dragBox
.
dragStart
(
e
.
getPosition
()
);
}
dragStartPosition
=
e
.
getPosition
();
},
mousemove
:
function
(
e
)
{
var
currentPosition
;
if
(
!
dragStartPosition
)
return
;
currentPosition
=
e
.
getPosition
();
if
(
!
dragBox
)
{
if
(
GM
.
getDistance
(
currentPosition
,
dragStartPosition
)
<
10
)
{
return
;
}
dragTargets
=
findAllAncestor
(
this
.
getSelectedNodes
().
slice
(
0
)
);
dropTargets
=
findAvailableParents
(
dragTargets
,
this
.
getRoot
()
);
dragBox
=
new
DragBox
(
dragTargets
.
map
(
function
(
target
)
{
return
target
.
getRenderContainer
();
}
),
currentPosition
);
this
.
getRenderContainer
().
addShape
(
dragBox
);
dragBox
.
shrink
();
}
dragBox
.
setTransform
(
new
kity
.
Matrix
().
translate
(
currentPosition
.
x
-
dragStartPosition
.
x
,
currentPosition
.
y
-
dragStartPosition
.
y
)
);
if
(
dropTarget
)
{
//dropTarget.getRenderContainer().scale( 0.8 );
dragBox
.
blue
();
dropTarget
=
null
;
}
dropTargets
.
forEach
(
function
(
test
)
{
if
(
!
dropTarget
&&
GM
.
isBoxIntersect
(
dragBox
.
getRenderBox
(),
test
.
getRenderContainer
().
getRenderBox
()
)
)
{
activeDropTarget
(
test
);
//test.getRenderContainer().scale( 1.25 );
dropTarget
=
test
;
dragBox
.
green
();
}
}
);
if
(
!
dropTarget
)
{
lastActivedDropTarget
=
null
;
}
this
.
_dragBox
.
dragMove
(
e
.
getPosition
()
);
},
mouseup
:
function
(
e
)
{
dragStartPosition
=
null
;
if
(
dragBox
)
{
dragBox
.
remove
();
dragBox
=
null
;
if
(
dropTarget
)
{
for
(
var
i
=
dragTargets
.
length
-
1
,
target
;
i
>=
0
;
i
--
)
{
target
=
dragTargets
[
i
];
if
(
target
.
parent
)
{
target
.
parent
.
removeChild
(
target
);
dropTarget
.
appendChild
(
target
);
}
}
this
.
removeAllSelectedNodes
();
this
.
initStyle
(
this
.
getRoot
()
);
}
}
this
.
_dragBox
.
dragEnd
();
}
},
commands
:
{
'movetoparent'
:
MoveToParentCommand
}
};
}
);
\ No newline at end of file
src/module/layout.default.js
View file @
0a07428c
...
...
@@ -121,7 +121,7 @@ KityMinder.registerModule( "LayoutDefault", function () {
case
"sub"
:
var
underline
=
Layout
.
underline
=
new
kity
.
Path
();
var
highlightshape
=
Layout
.
highlightshape
=
new
kity
.
Rect
().
setRadius
(
4
);
node
.
getBgRc
().
clear
().
addShapes
(
[
highlightshape
,
underline
]
);
node
.
getBgRc
().
clear
().
addShapes
(
[
Layout
.
bgRect
=
new
kity
.
Rect
().
setRadius
(
4
),
highlightshape
,
underline
]
);
break
;
default
:
break
;
...
...
@@ -160,6 +160,8 @@ KityMinder.registerModule( "LayoutDefault", function () {
case
"sub"
:
var
_contWidth
=
contRc
.
getWidth
();
var
_contHeight
=
contRc
.
getHeight
();
width
=
_contWidth
+
nodeStyle
.
padding
[
1
]
+
nodeStyle
.
padding
[
3
];
height
=
_contHeight
+
nodeStyle
.
padding
[
0
]
+
nodeStyle
.
padding
[
2
];
Layout
.
underline
.
getDrawer
()
.
clear
()
.
moveTo
(
0
,
_contHeight
+
nodeStyle
.
padding
[
2
]
+
nodeStyle
.
padding
[
0
]
)
...
...
@@ -168,6 +170,7 @@ KityMinder.registerModule( "LayoutDefault", function () {
Layout
.
highlightshape
.
setWidth
(
_contWidth
+
nodeStyle
.
padding
[
1
]
+
nodeStyle
.
padding
[
3
]
)
.
setHeight
(
_contHeight
+
nodeStyle
.
padding
[
0
]
+
nodeStyle
.
padding
[
2
]
);
Layout
.
bgRect
.
setWidth
(
width
).
setHeight
(
height
);
break
;
default
:
break
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment