Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
gojs-project
Overview
Overview
Details
Activity
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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
jlc
gojs-project
Commits
22b32890
Commit
22b32890
authored
Jun 11, 2024
by
jlc
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update:多个扩展的使用
parent
6f4acbc2
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1385 additions
and
2 deletions
+1385
-2
App.vue
src/App.vue
+4
-2
addPalette.vue
src/stageAchievements/addPalette.vue
+232
-0
GuidedDraggingTool.ts
src/stageAchievements/extensions/GuidedDraggingTool.ts
+556
-0
LinkLabelDraggingTools.ts
src/stageAchievements/extensions/LinkLabelDraggingTools.ts
+192
-0
NodeLabelDraggingTool.ts
src/stageAchievements/extensions/NodeLabelDraggingTool.ts
+167
-0
Robot.ts
src/stageAchievements/extensions/Robot.ts
+234
-0
No files found.
src/App.vue
View file @
22b32890
...
@@ -12,7 +12,8 @@
...
@@ -12,7 +12,8 @@
<!--
<contextMenu></contextMenu>
-->
<!--
<contextMenu></contextMenu>
-->
<!--
<firstProject></firstProject>
-->
<!--
<firstProject></firstProject>
-->
<!--
<port></port>
-->
<!--
<port></port>
-->
<dynamicPort></dynamicPort>
<!--
<dynamicPort></dynamicPort>
-->
<addPalette></addPalette>
</
template
>
</
template
>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
...
@@ -29,7 +30,8 @@
...
@@ -29,7 +30,8 @@
// import contextMenu from './components/contextMenu.vue';
// import contextMenu from './components/contextMenu.vue';
// import firstProject from './stageAchievements/firstProject.vue';
// import firstProject from './stageAchievements/firstProject.vue';
// import port from './components/port.vue';
// import port from './components/port.vue';
import
dynamicPort
from
'./stageAchievements/dynamicPort.vue'
;
// import dynamicPort from './stageAchievements/dynamicPort.vue';
import
addPalette
from
'./stageAchievements/addPalette.vue'
;
</
script
>
</
script
>
<
style
scoped
>
<
style
scoped
>
...
...
src/stageAchievements/addPalette.vue
0 → 100644
View file @
22b32890
<
template
>
<div
class=
"common-layout"
>
<div
class=
"layout-container"
>
<div
id=
"PaletteDiv"
class=
"layout-aside"
></div>
<div
id=
"diagramDiv"
class=
"layout-main"
></div>
</div>
</div>
<div>
<button
@
click=
"exportData"
>
导出数据
</button>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
onMounted
}
from
'vue'
;
import
go
from
'gojs'
;
import
{
PortShiftingTool
}
from
'./extensions/PortShiftingTool'
;
import
{
ResizeMultipleTool
}
from
'./extensions/ResizeMultipleTool'
;
import
{
LinkLabelDraggingTool
}
from
'./extensions/LinkLabelDraggingTools'
;
import
{
NodeLabelDraggingTool
}
from
'./extensions/NodeLabelDraggingTool'
;
import
{
GuidedDraggingTool
}
from
'./extensions/GuidedDraggingTool'
;
const
$
=
go
.
GraphObject
.
make
;
var
myDiagram
:
any
;
var
myPalette
:
any
;
function
initDiagram
()
{
myDiagram
=
$
(
go
.
Diagram
,
"diagramDiv"
,
{
"undoManager.isEnabled"
:
true
,
"toolManager.mouseWheelBehavior"
:
go
.
WheelMode
.
Zoom
,
resizingTool
:
new
ResizeMultipleTool
(),
// 自定义ResizeMultipleTool()方法来设置元素大小的缩放
draggingTool
:
new
GuidedDraggingTool
(),
// 使用节点对齐辅助
// 设置辅助对齐的线条的样式
"draggingTool.horizontalGuidelineColor"
:
"blue"
,
// 水平两侧的辅助线条为蓝色
"draggingTool.verticalGuidelineColor"
:
"blue"
,
// 垂直两侧的辅助线条为蓝色
"draggingTool.centerGuidelineColor"
:
"green"
,
// 节点中心的水平和垂直对齐的辅助线条为绿色
"draggingTool.guidelineWidth"
:
1
,
// 设置辅助对齐的线条的粗细
});
myDiagram
.
toolManager
.
mouseMoveTools
.
insertAt
(
0
,
new
PortShiftingTool
());
// 设置端口移动
myDiagram
.
toolManager
.
mouseMoveTools
.
insertAt
(
0
,
new
LinkLabelDraggingTool
());
// 设置链接上的文本可以移动
myDiagram
.
toolManager
.
mouseMoveTools
.
insertAt
(
0
,
new
NodeLabelDraggingTool
());
// 设置节点上的文本可以移动
myDiagram
.
nodeTemplate
=
$
(
go
.
Node
,
"Spot"
,
{
resizable
:
true
},
new
go
.
Binding
(
"location"
,
"loc"
),
new
go
.
Binding
(
"desiredSize"
,
"size"
,
go
.
Size
.
parse
).
makeTwoWay
(
go
.
Size
.
stringify
),
// 进行元素位置信息的绑定
$
(
go
.
Shape
,
"RoundedRectangle"
,
{
fill
:
"white"
,
strokeWidth
:
0
},
new
go
.
Binding
(
"fill"
,
"color"
)
),
$
(
go
.
TextBlock
,
{
margin
:
10
,
textAlign
:
'center'
,
font
:
'bold 14px Segoe UI,sans-serif'
,
stroke
:
'#484848'
,
editable
:
true
,
_isNodeLabel
:
true
,
cursor
:
"move"
},
new
go
.
Binding
(
'text'
,
'key'
).
makeTwoWay
(),
),
$
(
go
.
Shape
,
"Rectangle"
,
{
width
:
6
,
height
:
6
,
portId
:
"Top"
,
fromSpot
:
go
.
Spot
.
Top
,
// 从端口顶部发出连接
toSpot
:
go
.
Spot
.
Top
,
// 从端口顶部接收连接
fromLinkable
:
true
,
toLinkable
:
true
,
cursor
:
'pointer'
,
alignment
:
new
go
.
Spot
(
0.5
,
0
)
}
),
$
(
go
.
Shape
,
"Rectangle"
,
{
width
:
6
,
height
:
6
,
portId
:
"Left"
,
fromSpot
:
go
.
Spot
.
Left
,
toSpot
:
go
.
Spot
.
Left
,
fromLinkable
:
true
,
toLinkable
:
true
,
cursor
:
'pointer'
,
alignment
:
new
go
.
Spot
(
0
,
0.5
)
}
),
$
(
go
.
Shape
,
"Rectangle"
,
{
width
:
6
,
height
:
6
,
portId
:
"Right"
,
fromSpot
:
go
.
Spot
.
Right
,
toSpot
:
go
.
Spot
.
Right
,
fromLinkable
:
true
,
toLinkable
:
true
,
cursor
:
'pointer'
,
alignment
:
new
go
.
Spot
(
1
,
0.5
)
}
),
$
(
go
.
Shape
,
"Rectangle"
,
{
width
:
6
,
height
:
6
,
portId
:
"Bottom"
,
fromSpot
:
go
.
Spot
.
Bottom
,
toSpot
:
go
.
Spot
.
Bottom
,
fromLinkable
:
true
,
toLinkable
:
true
,
cursor
:
'pointer'
,
alignment
:
new
go
.
Spot
(
0.5
,
1
)
}
)
);
myPalette
=
$
(
go
.
Palette
,
"PaletteDiv"
,
{
nodeTemplate
:
myDiagram
.
nodeTemplate
,
model
:
new
go
.
GraphLinksModel
(
[
{
key
:
"Alpha"
,
color
:
"lightyellow"
},
{
key
:
"Beta"
,
color
:
"lightblue"
},
{
key
:
"Gamma"
,
color
:
"lightgreen"
},
{
key
:
"Delta"
,
color
:
"orange"
},
]
)
}
);
myDiagram
.
linkTemplate
=
$
(
go
.
Link
,
{
routing
:
go
.
Routing
.
AvoidsNodes
,
curve
:
go
.
Curve
.
JumpGap
,
corner
:
5
,
adjusting
:
go
.
LinkAdjusting
.
Stretch
,
reshapable
:
true
// 设置连接线的形态是否可以被修改
},
$
(
go
.
Shape
,
// 链接线的样式
{
strokeWidth
:
1.5
}
),
$
(
go
.
Shape
,
// 箭头的样式
{
toArrow
:
"standard"
,
stroke
:
null
}
),
$
(
go
.
Panel
,
"Auto"
,
{
cursor
:
"move"
},
// 用户可以使用此链接标签执行某些操作的视觉提示
$
(
go
.
Shape
,
// 设置链接中的标签样式
{
fill
:
"lightgray"
,
stroke
:
null
}
),
$
(
go
.
TextBlock
,
"transition"
,
// 设置链接中标签的文本样式
{
textAlign
:
"center"
,
font
:
"10pt helvetica, arial, sans-serif"
,
stroke
:
"black"
,
margin
:
4
,
editable
:
true
// 设置标签文本是否可编辑
},
new
go
.
Binding
(
"text"
,
"text"
).
makeTwoWay
()),
// 文本数据双向绑定
new
go
.
Binding
(
"segmentOffset"
,
"segmentOffset"
,
go
.
Point
.
parse
).
makeTwoWay
(
go
.
Point
.
stringify
)
)
);
const
nodeDataArray
=
[
{
key
:
"add1"
,
color
:
"lightyellow"
,
loc
:
new
go
.
Point
(
-
150
,
200
)
},
{
key
:
"add2"
,
color
:
"lightblue"
,
loc
:
new
go
.
Point
(
100
,
50
)
},
];
const
linkDataArray
=
[
{
from
:
"add1"
,
fromPort
:
"Top"
,
to
:
"add2"
,
toPort
:
"Left"
,
text
:
"hello"
},
];
myDiagram
.
model
=
$
(
go
.
GraphLinksModel
,
{
linkFromPortIdProperty
:
"fromPort"
,
linkToPortIdProperty
:
"toPort"
,
nodeDataArray
:
nodeDataArray
,
linkDataArray
:
linkDataArray
}
);
}
function
exportData
()
{
if
(
myDiagram
)
{
console
.
log
(
myDiagram
.
model
.
toJson
());
}
}
onMounted
(()
=>
{
initDiagram
()
});
</
script
>
<
style
>
.common-layout
{
display
:
flex
;
justify-content
:
space-between
;
}
.layout-container
{
display
:
flex
;
width
:
100%
;
}
.layout-aside
{
width
:
10%
;
height
:
900px
;
background-color
:
rgb
(
216
,
212
,
212
);
}
.layout-main
{
width
:
90%
;
height
:
900px
;
background-color
:
#DAE4E4
;
}
</
style
>
\ No newline at end of file
src/stageAchievements/extensions/GuidedDraggingTool.ts
0 → 100644
View file @
22b32890
/*
* Copyright (C) 1998-2024 by Northwoods Software Corporation. All Rights Reserved.
*/
/*
* This is an extension and not part of the main GoJS library.
* Note that the API for this class may change with any version, even point releases.
* If you intend to use an extension in production, you should copy the code to your own source directory.
* Extensions can be found in the GoJS kit under the extensions or extensionsJSM folders.
* See the Extensions intro page (https://gojs.net/latest/intro/extensions.html) for more information.
*/
import
*
as
go
from
'gojs'
;
/**
* The GuidedDraggingTool class makes guidelines visible as the parts are dragged around a diagram
* when the selected part is nearly aligned with another part.
*
* If you want to experiment with this extension, try the <a href="../../samples/GuidedDragging.html">Guided Dragging</a> sample.
* @category Tool Extension
*/
export
class
GuidedDraggingTool
extends
go
.
DraggingTool
{
// horizontal guidelines
guidelineHtop
:
go
.
Part
;
guidelineHbottom
:
go
.
Part
;
guidelineHcenter
:
go
.
Part
;
// vertical guidelines
guidelineVleft
:
go
.
Part
;
guidelineVright
:
go
.
Part
;
guidelineVcenter
:
go
.
Part
;
// properties that the programmer can modify
private
_guidelineSnapDistance
:
number
;
private
_isGuidelineEnabled
:
boolean
;
private
_horizontalGuidelineColor
:
string
;
private
_verticalGuidelineColor
:
string
;
private
_centerGuidelineColor
:
string
;
private
_guidelineWidth
:
number
;
private
_searchDistance
:
number
;
private
_isGuidelineSnapEnabled
:
boolean
;
/**
* Constructs a GuidedDraggingTool and sets up the temporary guideline parts.
*/
constructor
(
init
?:
Partial
<
GuidedDraggingTool
>
)
{
super
();
this
.
name
=
'GuidedDragging'
;
this
.
_guidelineSnapDistance
=
6
;
this
.
_isGuidelineEnabled
=
true
;
this
.
_horizontalGuidelineColor
=
'gray'
;
this
.
_verticalGuidelineColor
=
'gray'
;
this
.
_centerGuidelineColor
=
'gray'
;
this
.
_guidelineWidth
=
1
;
this
.
_searchDistance
=
1000
;
this
.
_isGuidelineSnapEnabled
=
true
;
const
partProperties
=
{
layerName
:
'Tool'
,
isInDocumentBounds
:
false
};
const
shapeProperties
=
{
stroke
:
'gray'
,
isGeometryPositioned
:
true
};
// temporary parts for horizonal guidelines
this
.
guidelineHtop
=
new
go
.
Part
(
partProperties
).
add
(
new
go
.
Shape
(
shapeProperties
).
set
({
geometryString
:
'M0 0 100 0'
})
);
this
.
guidelineHbottom
=
new
go
.
Part
(
partProperties
).
add
(
new
go
.
Shape
(
shapeProperties
).
set
({
geometryString
:
'M0 0 100 0'
})
);
this
.
guidelineHcenter
=
new
go
.
Part
(
partProperties
).
add
(
new
go
.
Shape
(
shapeProperties
).
set
({
geometryString
:
'M0 0 100 0'
})
);
// temporary parts for vertical guidelines
this
.
guidelineVleft
=
new
go
.
Part
(
partProperties
).
add
(
new
go
.
Shape
(
shapeProperties
).
set
({
geometryString
:
'M0 0 0 100'
})
);
this
.
guidelineVright
=
new
go
.
Part
(
partProperties
).
add
(
new
go
.
Shape
(
shapeProperties
).
set
({
geometryString
:
'M0 0 0 100'
})
);
this
.
guidelineVcenter
=
new
go
.
Part
(
partProperties
).
add
(
new
go
.
Shape
(
shapeProperties
).
set
({
geometryString
:
'M0 0 0 100'
})
);
if
(
init
)
Object
.
assign
(
this
,
init
);
}
/**
* Gets or sets the margin of error for which guidelines show up.
*
* The default value is 6.
* Guidelines will show up when the aligned nodes are ± 6px away from perfect alignment.
*/
get
guidelineSnapDistance
():
number
{
return
this
.
_guidelineSnapDistance
;
}
set
guidelineSnapDistance
(
val
:
number
)
{
if
(
typeof
val
!==
'number'
||
isNaN
(
val
)
||
val
<
0
)
throw
new
Error
(
'new value for GuidedDraggingTool.guidelineSnapDistance must be a non-negative number'
);
this
.
_guidelineSnapDistance
=
val
;
}
/**
* Gets or sets whether the guidelines are enabled or disables.
*
* The default value is true.
*/
get
isGuidelineEnabled
():
boolean
{
return
this
.
_isGuidelineEnabled
;
}
set
isGuidelineEnabled
(
val
:
boolean
)
{
if
(
typeof
val
!==
'boolean'
)
throw
new
Error
(
'new value for GuidedDraggingTool.isGuidelineEnabled must be a boolean value.'
);
this
.
_isGuidelineEnabled
=
val
;
}
/**
* Gets or sets the color of horizontal guidelines.
*
* The default value is "gray".
*/
get
horizontalGuidelineColor
():
string
{
return
this
.
_horizontalGuidelineColor
;
}
set
horizontalGuidelineColor
(
val
:
string
)
{
if
(
this
.
_horizontalGuidelineColor
!==
val
)
{
this
.
_horizontalGuidelineColor
=
val
;
if
(
this
.
guidelineHbottom
)
{
(
this
.
guidelineHbottom
.
elements
.
first
()
as
go
.
Shape
).
stroke
=
this
.
_horizontalGuidelineColor
;
}
if
(
this
.
guidelineHtop
)
{
(
this
.
guidelineHtop
.
elements
.
first
()
as
go
.
Shape
).
stroke
=
this
.
_horizontalGuidelineColor
;
}
}
}
/**
* Gets or sets the color of vertical guidelines.
*
* The default value is "gray".
*/
get
verticalGuidelineColor
():
string
{
return
this
.
_verticalGuidelineColor
;
}
set
verticalGuidelineColor
(
val
:
string
)
{
if
(
this
.
_verticalGuidelineColor
!==
val
)
{
this
.
_verticalGuidelineColor
=
val
;
if
(
this
.
guidelineVleft
)
{
(
this
.
guidelineVleft
.
elements
.
first
()
as
go
.
Shape
).
stroke
=
this
.
_verticalGuidelineColor
;
}
if
(
this
.
guidelineVright
)
{
(
this
.
guidelineVright
.
elements
.
first
()
as
go
.
Shape
).
stroke
=
this
.
_verticalGuidelineColor
;
}
}
}
/**
* Gets or sets the color of center guidelines.
*
* The default value is "gray".
*/
get
centerGuidelineColor
():
string
{
return
this
.
_centerGuidelineColor
;
}
set
centerGuidelineColor
(
val
:
string
)
{
if
(
this
.
_centerGuidelineColor
!==
val
)
{
this
.
_centerGuidelineColor
=
val
;
if
(
this
.
guidelineVcenter
)
{
(
this
.
guidelineVcenter
.
elements
.
first
()
as
go
.
Shape
).
stroke
=
this
.
_centerGuidelineColor
;
}
if
(
this
.
guidelineHcenter
)
{
(
this
.
guidelineHcenter
.
elements
.
first
()
as
go
.
Shape
).
stroke
=
this
.
_centerGuidelineColor
;
}
}
}
/**
* Gets or sets the strokeWidth of the guidelines.
*
* The default value is 1.
*/
get
guidelineWidth
():
number
{
return
this
.
_guidelineWidth
;
}
set
guidelineWidth
(
val
:
number
)
{
if
(
typeof
val
!==
'number'
||
isNaN
(
val
)
||
val
<
0
)
throw
new
Error
(
'New value for GuidedDraggingTool.guidelineWidth must be a non-negative number.'
);
if
(
this
.
_guidelineWidth
!==
val
)
{
this
.
_guidelineWidth
=
val
;
if
(
this
.
guidelineVcenter
)
{
(
this
.
guidelineVcenter
.
elements
.
first
()
as
go
.
Shape
).
strokeWidth
=
val
;
}
if
(
this
.
guidelineHcenter
)
{
(
this
.
guidelineHcenter
.
elements
.
first
()
as
go
.
Shape
).
strokeWidth
=
val
;
}
if
(
this
.
guidelineVleft
)
{
(
this
.
guidelineVleft
.
elements
.
first
()
as
go
.
Shape
).
strokeWidth
=
val
;
}
if
(
this
.
guidelineVright
)
{
(
this
.
guidelineVright
.
elements
.
first
()
as
go
.
Shape
).
strokeWidth
=
val
;
}
if
(
this
.
guidelineHbottom
)
{
(
this
.
guidelineHbottom
.
elements
.
first
()
as
go
.
Shape
).
strokeWidth
=
val
;
}
if
(
this
.
guidelineHtop
)
{
(
this
.
guidelineHtop
.
elements
.
first
()
as
go
.
Shape
).
strokeWidth
=
val
;
}
}
}
/**
* Gets or sets the distance around the selected part to search for aligned parts.
*
* The default value is 1000.
* Set this to Infinity if you want to search the entire diagram no matter how far away.
*/
get
searchDistance
():
number
{
return
this
.
_searchDistance
;
}
set
searchDistance
(
val
:
number
)
{
if
(
typeof
val
!==
'number'
||
isNaN
(
val
)
||
val
<=
0
)
throw
new
Error
(
'new value for GuidedDraggingTool.searchDistance must be a positive number.'
);
this
.
_searchDistance
=
val
;
}
/**
* Gets or sets whether snapping to guidelines is enabled.
*
* The default value is true.
*/
get
isGuidelineSnapEnabled
():
boolean
{
return
this
.
_isGuidelineSnapEnabled
;
}
set
isGuidelineSnapEnabled
(
val
:
boolean
)
{
if
(
typeof
val
!==
'boolean'
)
throw
new
Error
(
'new value for GuidedDraggingTool.isGuidelineSnapEnabled must be a boolean.'
);
this
.
_isGuidelineSnapEnabled
=
val
;
}
/**
* Removes all of the guidelines from the grid.
*/
clearGuidelines
():
void
{
if
(
this
.
guidelineHbottom
)
this
.
diagram
.
remove
(
this
.
guidelineHbottom
);
if
(
this
.
guidelineHcenter
)
this
.
diagram
.
remove
(
this
.
guidelineHcenter
);
if
(
this
.
guidelineHtop
)
this
.
diagram
.
remove
(
this
.
guidelineHtop
);
if
(
this
.
guidelineVleft
)
this
.
diagram
.
remove
(
this
.
guidelineVleft
);
if
(
this
.
guidelineVright
)
this
.
diagram
.
remove
(
this
.
guidelineVright
);
if
(
this
.
guidelineVcenter
)
this
.
diagram
.
remove
(
this
.
guidelineVcenter
);
}
/**
* Calls the base method and removes the guidelines from the graph.
*/
override
doDeactivate
():
void
{
super
.
doDeactivate
();
// clear any guidelines when dragging is done
this
.
clearGuidelines
();
}
/**
* Shows vertical and horizontal guidelines for the dragged part.
*/
override
doDragOver
(
pt
:
go
.
Point
,
obj
:
go
.
GraphObject
):
void
{
// clear all existing guidelines in case either show... method decides to show a guideline
this
.
clearGuidelines
();
// gets the selected part
const
draggingParts
=
this
.
copiedParts
||
this
.
draggedParts
;
if
(
draggingParts
===
null
)
return
;
const
partItr
=
draggingParts
.
iterator
;
if
(
partItr
.
next
())
{
const
part
=
partItr
.
key
;
this
.
showHorizontalMatches
(
part
,
this
.
isGuidelineEnabled
,
false
);
this
.
showVerticalMatches
(
part
,
this
.
isGuidelineEnabled
,
false
);
}
}
/**
* On a mouse-up, snaps the selected part to the nearest guideline.
* If not snapping, the part remains at its position.
*/
override
doDropOnto
(
pt
:
go
.
Point
,
obj
:
go
.
GraphObject
):
void
{
this
.
clearGuidelines
();
// gets the selected (perhaps copied) Part
const
draggingParts
=
this
.
copiedParts
||
this
.
draggedParts
;
if
(
draggingParts
===
null
)
return
;
const
partItr
=
draggingParts
.
iterator
;
if
(
partItr
.
next
())
{
const
part
=
partItr
.
key
;
// snaps only when the mouse is released without shift modifier
const
e
=
this
.
diagram
.
lastInput
;
const
snap
=
this
.
isGuidelineSnapEnabled
&&
!
e
.
shift
;
this
.
showHorizontalMatches
(
part
,
false
,
snap
);
// false means don't show guidelines
this
.
showVerticalMatches
(
part
,
false
,
snap
);
}
}
/**
* When nodes are shifted due to being guided upon a drop, make sure all connected link routes are invalidated,
* since the node is likely to have moved a different amount than all its connected links in the regular
* operation of the DraggingTool.
*/
invalidateLinks
(
node
:
go
.
Part
):
void
{
if
(
node
instanceof
go
.
Node
)
node
.
invalidateConnectedLinks
();
}
/**
* This predicate decides whether or not the given Part should guide the dragged part.
* @param part - a stationary Part to which the dragged part might be aligned
* @param guidedpart - the Part being dragged
*/
protected
isGuiding
(
part
:
go
.
Part
,
guidedpart
:
go
.
Part
):
boolean
{
return
(
part
instanceof
go
.
Part
&&
!
part
.
isSelected
&&
!
(
part
instanceof
go
.
Link
)
&&
guidedpart
instanceof
go
.
Part
&&
part
.
containingGroup
===
guidedpart
.
containingGroup
&&
part
.
layer
!==
null
&&
!
part
.
layer
.
isTemporary
);
}
/**
* This finds parts that are aligned near the selected part along horizontal lines. It compares the selected
* part to all parts within a rectangle approximately twice the {@link searchDistance} wide.
* The guidelines appear when a part is aligned within a margin-of-error equal to {@link guidelineSnapDistance}.
* @param part
* @param guideline - if true, show guideline
* @param snap - if true, snap the part to where the guideline would be
*/
showHorizontalMatches
(
part
:
go
.
Part
,
guideline
:
boolean
,
snap
:
boolean
):
void
{
const
objBounds
=
part
.
locationObject
.
getDocumentBounds
();
const
p0
=
objBounds
.
y
;
const
p1
=
objBounds
.
y
+
objBounds
.
height
/
2
;
const
p2
=
objBounds
.
y
+
objBounds
.
height
;
const
marginOfError
=
this
.
guidelineSnapDistance
;
let
distance
=
this
.
searchDistance
;
if
(
distance
===
Infinity
)
distance
=
this
.
diagram
.
documentBounds
.
width
;
// compares with parts within narrow vertical area
const
area
=
objBounds
.
copy
();
area
.
inflate
(
distance
,
marginOfError
+
1
);
const
otherObjs
=
this
.
diagram
.
findObjectsIn
(
area
,
(
obj
)
=>
obj
.
part
as
go
.
Part
,
(
p
)
=>
this
.
isGuiding
(
p
as
go
.
Part
,
part
),
true
)
as
go
.
Set
<
go
.
Part
>
;
let
bestDiff
:
number
=
marginOfError
;
let
bestObj
:
any
=
null
;
// TS 2.6 won't let this be go.Part | null
let
bestSpot
:
go
.
Spot
=
go
.
Spot
.
Default
;
let
bestOtherSpot
:
go
.
Spot
=
go
.
Spot
.
Default
;
// horizontal line -- comparing y-values
otherObjs
.
each
((
other
)
=>
{
if
(
other
===
part
)
return
;
// ignore itself
const
otherBounds
=
other
.
locationObject
.
getDocumentBounds
();
const
q0
=
otherBounds
.
y
;
const
q1
=
otherBounds
.
y
+
otherBounds
.
height
/
2
;
const
q2
=
otherBounds
.
y
+
otherBounds
.
height
;
// compare center with center of OTHER part
if
(
this
.
guidelineHcenter
&&
Math
.
abs
(
p1
-
q1
)
<
bestDiff
)
{
bestDiff
=
Math
.
abs
(
p1
-
q1
);
bestObj
=
other
;
bestSpot
=
go
.
Spot
.
Center
;
bestOtherSpot
=
go
.
Spot
.
Center
;
}
// compare top side with top and bottom sides of OTHER part
if
(
this
.
guidelineHtop
&&
Math
.
abs
(
p0
-
q0
)
<
bestDiff
)
{
bestDiff
=
Math
.
abs
(
p0
-
q0
);
bestObj
=
other
;
bestSpot
=
go
.
Spot
.
Top
;
bestOtherSpot
=
go
.
Spot
.
Top
;
}
else
if
(
this
.
guidelineHtop
&&
Math
.
abs
(
p0
-
q2
)
<
bestDiff
)
{
bestDiff
=
Math
.
abs
(
p0
-
q2
);
bestObj
=
other
;
bestSpot
=
go
.
Spot
.
Top
;
bestOtherSpot
=
go
.
Spot
.
Bottom
;
}
// compare bottom side with top and bottom sides of OTHER part
if
(
this
.
guidelineHbottom
&&
Math
.
abs
(
p2
-
q0
)
<
bestDiff
)
{
bestDiff
=
Math
.
abs
(
p2
-
q0
);
bestObj
=
other
;
bestSpot
=
go
.
Spot
.
Bottom
;
bestOtherSpot
=
go
.
Spot
.
Top
;
}
else
if
(
this
.
guidelineHbottom
&&
Math
.
abs
(
p2
-
q2
)
<
bestDiff
)
{
bestDiff
=
Math
.
abs
(
p2
-
q2
);
bestObj
=
other
;
bestSpot
=
go
.
Spot
.
Bottom
;
bestOtherSpot
=
go
.
Spot
.
Bottom
;
}
});
if
(
bestObj
!==
null
)
{
const
offsetX
=
objBounds
.
x
-
part
.
actualBounds
.
x
;
const
offsetY
=
objBounds
.
y
-
part
.
actualBounds
.
y
;
const
bestBounds
=
bestObj
.
locationObject
.
getDocumentBounds
();
// line extends from x0 to x2
const
x0
=
Math
.
min
(
objBounds
.
x
,
bestBounds
.
x
)
-
10
;
const
x2
=
Math
.
max
(
objBounds
.
x
+
objBounds
.
width
,
bestBounds
.
x
+
bestBounds
.
width
)
+
10
;
// find bestObj's desired Y
const
bestPoint
=
new
go
.
Point
().
setRectSpot
(
bestBounds
,
bestOtherSpot
);
if
(
bestSpot
===
go
.
Spot
.
Center
)
{
if
(
snap
)
{
// call Part.move in order to automatically move member Parts of Groups
part
.
move
(
new
go
.
Point
(
objBounds
.
x
-
offsetX
,
bestPoint
.
y
-
objBounds
.
height
/
2
-
offsetY
)
);
this
.
invalidateLinks
(
part
);
}
if
(
guideline
)
{
this
.
guidelineHcenter
.
position
=
new
go
.
Point
(
x0
,
bestPoint
.
y
);
this
.
guidelineHcenter
.
elt
(
0
).
width
=
x2
-
x0
;
this
.
diagram
.
add
(
this
.
guidelineHcenter
);
}
}
else
if
(
bestSpot
===
go
.
Spot
.
Top
)
{
if
(
snap
)
{
part
.
move
(
new
go
.
Point
(
objBounds
.
x
-
offsetX
,
bestPoint
.
y
-
offsetY
));
this
.
invalidateLinks
(
part
);
}
if
(
guideline
)
{
this
.
guidelineHtop
.
position
=
new
go
.
Point
(
x0
,
bestPoint
.
y
);
this
.
guidelineHtop
.
elt
(
0
).
width
=
x2
-
x0
;
this
.
diagram
.
add
(
this
.
guidelineHtop
);
}
}
else
if
(
bestSpot
===
go
.
Spot
.
Bottom
)
{
if
(
snap
)
{
part
.
move
(
new
go
.
Point
(
objBounds
.
x
-
offsetX
,
bestPoint
.
y
-
objBounds
.
height
-
offsetY
));
this
.
invalidateLinks
(
part
);
}
if
(
guideline
)
{
this
.
guidelineHbottom
.
position
=
new
go
.
Point
(
x0
,
bestPoint
.
y
);
this
.
guidelineHbottom
.
elt
(
0
).
width
=
x2
-
x0
;
this
.
diagram
.
add
(
this
.
guidelineHbottom
);
}
}
}
}
/**
* This finds parts that are aligned near the selected part along vertical lines. It compares the selected
* part to all parts within a rectangle approximately twice the {@link searchDistance} tall.
* The guidelines appear when a part is aligned within a margin-of-error equal to {@link guidelineSnapDistance}.
* @param part
* @param guideline - if true, show guideline
* @param snap - if true, don't show guidelines but just snap the part to where the guideline would be
*/
showVerticalMatches
(
part
:
go
.
Part
,
guideline
:
boolean
,
snap
:
boolean
):
void
{
const
objBounds
=
part
.
locationObject
.
getDocumentBounds
();
const
p0
=
objBounds
.
x
;
const
p1
=
objBounds
.
x
+
objBounds
.
width
/
2
;
const
p2
=
objBounds
.
x
+
objBounds
.
width
;
const
marginOfError
=
this
.
guidelineSnapDistance
;
let
distance
=
this
.
searchDistance
;
if
(
distance
===
Infinity
)
distance
=
this
.
diagram
.
documentBounds
.
height
;
// compares with parts within narrow vertical area
const
area
=
objBounds
.
copy
();
area
.
inflate
(
marginOfError
+
1
,
distance
);
const
otherObjs
=
this
.
diagram
.
findObjectsIn
(
area
,
(
obj
)
=>
obj
.
part
as
go
.
Part
,
(
p
)
=>
this
.
isGuiding
(
p
as
go
.
Part
,
part
),
true
)
as
go
.
Set
<
go
.
Part
>
;
let
bestDiff
:
number
=
marginOfError
;
let
bestObj
:
any
=
null
;
// TS 2.6 won't let this be go.Part | null
let
bestSpot
:
go
.
Spot
=
go
.
Spot
.
Default
;
let
bestOtherSpot
:
go
.
Spot
=
go
.
Spot
.
Default
;
// vertical line -- comparing x-values
otherObjs
.
each
((
other
)
=>
{
if
(
other
===
part
)
return
;
// ignore itself
const
otherBounds
=
other
.
locationObject
.
getDocumentBounds
();
const
q0
=
otherBounds
.
x
;
const
q1
=
otherBounds
.
x
+
otherBounds
.
width
/
2
;
const
q2
=
otherBounds
.
x
+
otherBounds
.
width
;
// compare center with center of OTHER part
if
(
this
.
guidelineVcenter
&&
Math
.
abs
(
p1
-
q1
)
<
bestDiff
)
{
bestDiff
=
Math
.
abs
(
p1
-
q1
);
bestObj
=
other
;
bestSpot
=
go
.
Spot
.
Center
;
bestOtherSpot
=
go
.
Spot
.
Center
;
}
// compare left side with left and right sides of OTHER part
if
(
this
.
guidelineVleft
&&
Math
.
abs
(
p0
-
q0
)
<
bestDiff
)
{
bestDiff
=
Math
.
abs
(
p0
-
q0
);
bestObj
=
other
;
bestSpot
=
go
.
Spot
.
Left
;
bestOtherSpot
=
go
.
Spot
.
Left
;
}
else
if
(
this
.
guidelineVleft
&&
Math
.
abs
(
p0
-
q2
)
<
bestDiff
)
{
bestDiff
=
Math
.
abs
(
p0
-
q2
);
bestObj
=
other
;
bestSpot
=
go
.
Spot
.
Left
;
bestOtherSpot
=
go
.
Spot
.
Right
;
}
// compare right side with left and right sides of OTHER part
if
(
this
.
guidelineVright
&&
Math
.
abs
(
p2
-
q0
)
<
bestDiff
)
{
bestDiff
=
Math
.
abs
(
p2
-
q0
);
bestObj
=
other
;
bestSpot
=
go
.
Spot
.
Right
;
bestOtherSpot
=
go
.
Spot
.
Left
;
}
else
if
(
this
.
guidelineVright
&&
Math
.
abs
(
p2
-
q2
)
<
bestDiff
)
{
bestDiff
=
Math
.
abs
(
p2
-
q2
);
bestObj
=
other
;
bestSpot
=
go
.
Spot
.
Right
;
bestOtherSpot
=
go
.
Spot
.
Right
;
}
});
if
(
bestObj
!==
null
)
{
const
offsetX
=
objBounds
.
x
-
part
.
actualBounds
.
x
;
const
offsetY
=
objBounds
.
y
-
part
.
actualBounds
.
y
;
const
bestBounds
=
bestObj
.
locationObject
.
getDocumentBounds
();
// line extends from y0 to y2
const
y0
=
Math
.
min
(
objBounds
.
y
,
bestBounds
.
y
)
-
10
;
const
y2
=
Math
.
max
(
objBounds
.
y
+
objBounds
.
height
,
bestBounds
.
y
+
bestBounds
.
height
)
+
10
;
// find bestObj's desired X
const
bestPoint
=
new
go
.
Point
().
setRectSpot
(
bestBounds
,
bestOtherSpot
);
if
(
bestSpot
===
go
.
Spot
.
Center
)
{
if
(
snap
)
{
// call Part.move in order to automatically move member Parts of Groups
part
.
move
(
new
go
.
Point
(
bestPoint
.
x
-
objBounds
.
width
/
2
-
offsetX
,
objBounds
.
y
-
offsetY
)
);
this
.
invalidateLinks
(
part
);
}
if
(
guideline
)
{
this
.
guidelineVcenter
.
position
=
new
go
.
Point
(
bestPoint
.
x
,
y0
);
this
.
guidelineVcenter
.
elt
(
0
).
height
=
y2
-
y0
;
this
.
diagram
.
add
(
this
.
guidelineVcenter
);
}
}
else
if
(
bestSpot
===
go
.
Spot
.
Left
)
{
if
(
snap
)
{
part
.
move
(
new
go
.
Point
(
bestPoint
.
x
-
offsetX
,
objBounds
.
y
-
offsetY
));
this
.
invalidateLinks
(
part
);
}
if
(
guideline
)
{
this
.
guidelineVleft
.
position
=
new
go
.
Point
(
bestPoint
.
x
,
y0
);
this
.
guidelineVleft
.
elt
(
0
).
height
=
y2
-
y0
;
this
.
diagram
.
add
(
this
.
guidelineVleft
);
}
}
else
if
(
bestSpot
===
go
.
Spot
.
Right
)
{
if
(
snap
)
{
part
.
move
(
new
go
.
Point
(
bestPoint
.
x
-
objBounds
.
width
-
offsetX
,
objBounds
.
y
-
offsetY
));
this
.
invalidateLinks
(
part
);
}
if
(
guideline
)
{
this
.
guidelineVright
.
position
=
new
go
.
Point
(
bestPoint
.
x
,
y0
);
this
.
guidelineVright
.
elt
(
0
).
height
=
y2
-
y0
;
this
.
diagram
.
add
(
this
.
guidelineVright
);
}
}
}
}
}
src/stageAchievements/extensions/LinkLabelDraggingTools.ts
0 → 100644
View file @
22b32890
/*
* Copyright (C) 1998-2024 by Northwoods Software Corporation. All Rights Reserved.
*/
/*
* This is an extension and not part of the main GoJS library.
* Note that the API for this class may change with any version, even point releases.
* If you intend to use an extension in production, you should copy the code to your own source directory.
* Extensions can be found in the GoJS kit under the extensions or extensionsJSM folders.
* See the Extensions intro page (https://gojs.net/latest/intro/extensions.html) for more information.
*/
import
*
as
go
from
'gojs'
;
/**
* The LinkLabelDraggingTool class lets the user move a label on a {@link go.Link}.
*
* This tool only works when the Link has a label
* that is positioned at the {@link go.Link.midPoint} plus some offset.
* It does not work for labels that have a particular {@link go.GraphObject.segmentIndex}.
*
* If you want to experiment with this extension, try the <a href="../../samples/LinkLabelDragging.html">Link Label Dragging</a> sample.
* @category Tool Extension
*/
export
class
LinkLabelDraggingTool
extends
go
.
Tool
{
/**
* The label being dragged.
*/
label
:
go
.
GraphObject
|
null
;
private
_offset
:
go
.
Point
;
// of the mouse relative to the center of the label object
private
_originalOffset
:
go
.
Point
|
null
;
/**
* Constructs a LinkLabelDraggingTool and sets the name for the tool.
*/
constructor
(
init
?:
Partial
<
LinkLabelDraggingTool
>
)
{
super
();
this
.
name
=
'LinkLabelDragging'
;
this
.
label
=
null
;
this
.
_offset
=
new
go
.
Point
();
this
.
_originalOffset
=
null
;
if
(
init
)
Object
.
assign
(
this
,
init
);
}
/**
* From the GraphObject at the mouse point, search up the visual tree until we get to
* an object that is a label of a Link.
* @returns This returns null if no such label is at the mouse down point.
*/
findLabel
():
go
.
GraphObject
|
null
{
const
diagram
=
this
.
diagram
;
const
e
=
diagram
.
lastInput
;
let
elt
=
diagram
.
findObjectAt
(
e
.
documentPoint
,
null
,
null
);
if
(
elt
===
null
||
!
(
elt
.
part
instanceof
go
.
Link
))
return
null
;
while
(
elt
!==
null
&&
elt
.
panel
!==
elt
.
part
)
{
elt
=
elt
.
panel
;
}
// If it's at an arrowhead segment index, don't consider it a label:
if
(
elt
!==
null
&&
(
elt
.
segmentIndex
===
0
||
elt
.
segmentIndex
===
-
1
))
return
null
;
return
elt
;
}
/**
* This tool can only start if the mouse has moved enough so that it is not a click,
* and if the mouse down point is on a GraphObject "label" in a Link Panel,
* as determined by {@link findLabel}.
*/
override
canStart
():
boolean
{
if
(
!
super
.
canStart
())
return
false
;
const
diagram
=
this
.
diagram
;
// require left button & that it has moved far enough away from the mouse down point, so it isn't a click
const
e
=
diagram
.
lastInput
;
if
(
!
e
.
left
)
return
false
;
if
(
!
this
.
isBeyondDragSize
())
return
false
;
return
this
.
findLabel
()
!==
null
;
}
/**
* Start a transaction, call {@link findLabel} and remember it as the "label" property,
* and remember the original value for the label's {@link go.GraphObject.segmentOffset} property.
*/
override
doActivate
():
void
{
this
.
startTransaction
(
'Shifted Label'
);
this
.
label
=
this
.
findLabel
();
if
(
this
.
label
!==
null
)
{
// compute the offset of the mouse-down point relative to the center of the label
this
.
_offset
=
this
.
diagram
.
firstInput
.
documentPoint
.
copy
()
.
subtract
(
this
.
label
.
getDocumentPoint
(
go
.
Spot
.
Center
));
this
.
_originalOffset
=
this
.
label
.
segmentOffset
.
copy
();
}
super
.
doActivate
();
}
/**
* Stop any ongoing transaction.
*/
override
doDeactivate
():
void
{
super
.
doDeactivate
();
this
.
stopTransaction
();
}
/**
* Clear any reference to a label element.
*/
override
doStop
():
void
{
this
.
label
=
null
;
super
.
doStop
();
}
/**
* Restore the label's original value for {@link go.GraphObject.segmentOffset}.
*/
override
doCancel
():
void
{
if
(
this
.
label
!==
null
&&
this
.
_originalOffset
!==
null
)
{
this
.
label
.
segmentOffset
=
this
.
_originalOffset
;
}
super
.
doCancel
();
}
/**
* During the drag, call {@link updateSegmentOffset} in order to set
* the {@link go.GraphObject.segmentOffset} of the label.
*/
override
doMouseMove
():
void
{
if
(
!
this
.
isActive
)
return
;
this
.
updateSegmentOffset
();
}
/**
* At the end of the drag, update the segment offset of the label and finish the tool,
* completing a transaction.
*/
override
doMouseUp
():
void
{
if
(
!
this
.
isActive
)
return
;
this
.
updateSegmentOffset
();
this
.
transactionResult
=
'Shifted Label'
;
this
.
stopTool
();
}
/**
* Save the label's {@link go.GraphObject.segmentOffset} as a rotated offset from the midpoint of the
* Link that the label is in.
*/
updateSegmentOffset
():
void
{
const
lab
=
this
.
label
;
if
(
lab
===
null
)
return
;
const
link
=
lab
.
part
;
if
(
!
(
link
instanceof
go
.
Link
))
return
;
const
last
=
this
.
diagram
.
lastInput
.
documentPoint
;
const
idx
=
lab
.
segmentIndex
;
const
numpts
=
link
.
pointsCount
;
if
(
isNaN
(
idx
)
&&
link
.
path
)
{
// handle fractions along the whole path
const
labpt
=
link
.
path
.
getDocumentPoint
(
link
.
geometry
.
getPointAlongPath
(
lab
.
segmentFraction
)
);
const
angle
=
link
.
geometry
.
getAngleAlongPath
(
lab
.
segmentFraction
);
const
p
=
new
go
.
Point
(
last
.
x
-
this
.
_offset
.
x
-
labpt
.
x
,
last
.
y
-
this
.
_offset
.
y
-
labpt
.
y
);
lab
.
segmentOffset
=
p
.
rotate
(
-
angle
);
}
else
if
(
idx
<
-
numpts
||
idx
>=
numpts
)
{
// if the label is a "mid" label, assume it is positioned differently from a label at a particular segment
const
mid
=
link
.
midPoint
;
// need to rotate this point to account for the angle of the link segment at the mid-point
const
p
=
new
go
.
Point
(
last
.
x
-
this
.
_offset
.
x
-
mid
.
x
,
last
.
y
-
this
.
_offset
.
y
-
mid
.
y
);
lab
.
segmentOffset
=
p
.
rotate
(
-
link
.
midAngle
);
}
else
{
// handle the label point being on a partiular segment with a given fraction
const
frac
=
lab
.
segmentFraction
;
let
a
:
go
.
Point
;
let
b
:
go
.
Point
;
if
(
idx
>=
0
)
{
// indexing forwards
a
=
link
.
getPoint
(
idx
);
b
=
idx
<
numpts
-
1
?
link
.
getPoint
(
idx
+
1
)
:
a
;
}
else
{
// or backwards if segmentIndex is negative
const
i
=
numpts
+
idx
;
a
=
link
.
getPoint
(
i
);
b
=
i
>
0
?
link
.
getPoint
(
i
-
1
)
:
a
;
}
const
labx
=
a
.
x
+
(
b
.
x
-
a
.
x
)
*
frac
;
const
laby
=
a
.
y
+
(
b
.
y
-
a
.
y
)
*
frac
;
const
p
=
new
go
.
Point
(
last
.
x
-
this
.
_offset
.
x
-
labx
,
last
.
y
-
this
.
_offset
.
y
-
laby
);
const
segangle
=
idx
>=
0
?
a
.
directionPoint
(
b
)
:
b
.
directionPoint
(
a
);
lab
.
segmentOffset
=
p
.
rotate
(
-
segangle
);
}
}
}
src/stageAchievements/extensions/NodeLabelDraggingTool.ts
0 → 100644
View file @
22b32890
/*
* Copyright (C) 1998-2024 by Northwoods Software Corporation. All Rights Reserved.
*/
/*
* This is an extension and not part of the main GoJS library.
* Note that the API for this class may change with any version, even point releases.
* If you intend to use an extension in production, you should copy the code to your own source directory.
* Extensions can be found in the GoJS kit under the extensions or extensionsJSM folders.
* See the Extensions intro page (https://gojs.net/latest/intro/extensions.html) for more information.
*/
import
*
as
go
from
'gojs'
;
/**
* The NodeLabelDraggingTool class lets the user move a label on a Node.
*
* This tool only works when the Node has a label (any GraphObject) marked with
* `{ _isNodeLabel: true }` that is positioned in a Spot Panel.
* It works by modifying that label's {@link go.GraphObject.alignment} property to have an
* offset from the center of the panel.
*
* If you want to experiment with this extension, try the <a href="../../samples/NodeLabelDragging.html">Node Label Dragging</a> sample.
* @category Tool Extension
*/
export
class
NodeLabelDraggingTool
extends
go
.
Tool
{
/**
* The label being dragged.
*/
label
:
go
.
GraphObject
|
null
;
private
_offset
:
go
.
Point
;
// of the mouse relative to the center of the label object
private
_originalAlignment
:
go
.
Spot
;
private
_originalCenter
:
go
.
Point
;
/**
* Constructs a NodeLabelDraggingTool and sets the name for the tool.
*/
constructor
(
init
?:
Partial
<
NodeLabelDraggingTool
>
)
{
super
();
this
.
name
=
'NodeLabelDragging'
;
this
.
label
=
null
;
this
.
_offset
=
new
go
.
Point
();
this
.
_originalAlignment
=
go
.
Spot
.
Default
;
this
.
_originalCenter
=
new
go
.
Point
();
if
(
init
)
Object
.
assign
(
this
,
init
);
}
/**
* From the GraphObject at the mouse point, search up the visual tree until we get to
* an object that has the "_isNodeLabel" property set to true, that is in a Spot Panel,
* and that is not the first element of that Panel (i.e. not the main element of the panel).
* @returns This returns null if no such label is at the mouse down point.
*/
findLabel
():
go
.
GraphObject
|
null
{
const
diagram
=
this
.
diagram
;
const
e
=
diagram
.
firstInput
;
let
elt
=
diagram
.
findObjectAt
(
e
.
documentPoint
,
null
,
null
);
if
(
elt
===
null
||
!
(
elt
.
part
instanceof
go
.
Node
))
return
null
;
while
(
elt
.
panel
!==
null
)
{
if
((
elt
as
any
)[
'_isNodeLabel'
]
&&
elt
.
panel
.
type
===
go
.
Panel
.
Spot
&&
elt
.
panel
.
findMainElement
()
!==
elt
)
return
elt
;
elt
=
elt
.
panel
;
}
return
null
;
}
/**
* This tool can only start if the mouse has moved enough so that it is not a click,
* and if the mouse down point is on a GraphObject "label" in a Spot Panel,
* as determined by findLabel().
*/
override
canStart
():
boolean
{
if
(
!
super
.
canStart
())
return
false
;
const
diagram
=
this
.
diagram
;
// require left button & that it has moved far enough away from the mouse down point, so it isn't a click
const
e
=
diagram
.
lastInput
;
if
(
!
e
.
left
)
return
false
;
if
(
!
this
.
isBeyondDragSize
())
return
false
;
return
this
.
findLabel
()
!==
null
;
}
/**
* Start a transaction, call {@link findLabel} and remember it as the "label" property,
* and remember the original value for the label's {@link go.GraphObject.alignment} property.
*/
override
doActivate
():
void
{
this
.
startTransaction
(
'Shifted Label'
);
this
.
label
=
this
.
findLabel
();
if
(
this
.
label
!==
null
)
{
// compute the offset of the mouse-down point relative to the center of the label
this
.
_offset
=
this
.
diagram
.
firstInput
.
documentPoint
.
copy
()
.
subtract
(
this
.
label
.
getDocumentPoint
(
go
.
Spot
.
Center
));
this
.
_originalAlignment
=
this
.
label
.
alignment
.
copy
();
const
panel
=
this
.
label
.
panel
;
if
(
panel
!==
null
)
{
const
main
=
panel
.
findMainElement
();
if
(
main
!==
null
)
this
.
_originalCenter
=
main
.
getDocumentPoint
(
go
.
Spot
.
Center
);
}
}
super
.
doActivate
();
}
/**
* Stop any ongoing transaction.
*/
override
doDeactivate
():
void
{
super
.
doDeactivate
();
this
.
stopTransaction
();
}
/**
* Clear any reference to a label element.
*/
override
doStop
():
void
{
this
.
label
=
null
;
super
.
doStop
();
}
/**
* Restore the label's original value for GraphObject.alignment.
*/
override
doCancel
():
void
{
if
(
this
.
label
!==
null
)
{
this
.
label
.
alignment
=
this
.
_originalAlignment
;
}
super
.
doCancel
();
}
/**
* During the drag, call updateAlignment in order to set the {@link go.GraphObject.alignment} of the label.
*/
override
doMouseMove
():
void
{
if
(
!
this
.
isActive
)
return
;
this
.
updateAlignment
();
}
/**
* At the end of the drag, update the alignment of the label and finish the tool,
* completing a transaction.
*/
override
doMouseUp
():
void
{
if
(
!
this
.
isActive
)
return
;
this
.
updateAlignment
();
this
.
transactionResult
=
'Shifted Label'
;
this
.
stopTool
();
}
/**
* Save the label's {@link go.GraphObject.alignment} as an absolute offset from the center of the Spot Panel
* that the label is in.
*/
updateAlignment
():
void
{
if
(
this
.
label
===
null
)
return
;
const
last
=
this
.
diagram
.
lastInput
.
documentPoint
;
const
cntr
=
this
.
_originalCenter
;
this
.
label
.
alignment
=
new
go
.
Spot
(
0.5
,
0.5
,
last
.
x
-
this
.
_offset
.
x
-
cntr
.
x
,
last
.
y
-
this
.
_offset
.
y
-
cntr
.
y
);
}
}
src/stageAchievements/extensions/Robot.ts
0 → 100644
View file @
22b32890
/*
* Copyright (C) 1998-2024 by Northwoods Software Corporation. All Rights Reserved.
*/
/*
* This is an extension and not part of the main GoJS library.
* Note that the API for this class may change with any version, even point releases.
* If you intend to use an extension in production, you should copy the code to your own source directory.
* Extensions can be found in the GoJS kit under the extensions or extensionsJSM folders.
* See the Extensions intro page (https://gojs.net/latest/intro/extensions.html) for more information.
*/
import
*
as
go
from
'gojs'
;
/**
* A class for simulating mouse and keyboard input.
*
* As a special feature, this supports limited simulation of drag-and-drop between Diagrams,
* by setting both the `sourceDiagram` and `targetDiagram` properties
* on the `eventprops` argument of the mouseDown/mouseMove/mouseUp methods.
* Although {@link go.InputEvent.targetDiagram} is a real property,
* the `sourceDiagram` property is only used by these Robot methods.
*
* Typical setup:
* ```js
* // a shared Robot that can be used by all commands for this one Diagram
* myRobot = new Robot(myDiagram); // defined in Robot.js
* ```
* Then later:
* ```js
* // Simulate a mouse drag to move a node:
* const loc = ...; // some Point in document coordinates that is within the bounds of a node
* const options = {}; // possible settings of InputEvent, such as setting control or shift to true
* myRobot.mouseDown(loc.x, loc.y, 0, options);
* myRobot.mouseMove(loc.x + 80, loc.y + 50, 50, options);
* myRobot.mouseMove(loc.x + 20, loc.y + 100, 100, options);
* myRobot.mouseUp(loc.x + 20, loc.y + 100, 150, options);
* ```
*
* If you want to experiment with this extension, try the <a href="../../samples/Robot.html">Simulating Input</a> sample.
* @category Extension
*/
export
class
Robot
{
private
_diagram
:
go
.
Diagram
;
/**
* Construct a robot for a given {@link go.Diagram}. If none is provided, a new Diagram will be created.
*/
constructor
(
dia
?:
go
.
Diagram
)
{
if
(
dia
instanceof
go
.
Diagram
)
{
this
.
_diagram
=
dia
;
}
else
{
this
.
_diagram
=
new
go
.
Diagram
();
}
}
/**
* Gets or sets the {@link go.Diagram} associated with this Robot.
*/
get
diagram
():
go
.
Diagram
{
return
this
.
_diagram
;
}
set
diagram
(
val
:
go
.
Diagram
)
{
if
(
!
(
val
instanceof
go
.
Diagram
))
throw
new
Error
(
'Robot.diagram must be a Diagram, not: '
+
val
);
this
.
_diagram
=
val
;
}
/**
* @hidden @internal
* Transfer property settings from a JavaScript Object to an {@link go.InputEvent}.
*/
initializeEvent
(
e
:
go
.
InputEvent
,
props
?:
go
.
ObjectData
):
void
{
if
(
!
props
)
return
;
for
(
const
p
in
props
)
{
if
(
p
!==
'sourceDiagram'
)
(
e
as
any
)[
p
]
=
(
props
as
any
)[
p
];
}
}
/**
* Simulate a mouse down event.
* @param x - the X-coordinate of the mouse point in document coordinates.
* @param y - the Y-coordinate of the mouse point in document coordinates.
* @param time - the timestamp of the simulated event, in milliseconds; default zero
* @param eventprops - an optional argument providing properties for the InputEvent.
*/
mouseDown
(
x
:
number
,
y
:
number
,
time
?:
number
,
eventprops
?:
go
.
ObjectData
):
void
{
if
(
typeof
x
!==
'number'
||
typeof
y
!==
'number'
)
throw
new
Error
(
'Robot.mouseDown first two args must be X,Y numbers'
);
if
(
time
===
undefined
)
time
=
0
;
let
diagram
=
this
.
_diagram
;
if
(
eventprops
&&
(
eventprops
as
any
).
sourceDiagram
)
diagram
=
(
eventprops
as
any
).
sourceDiagram
;
if
(
!
diagram
.
isEnabled
)
return
;
const
n
=
new
go
.
InputEvent
();
n
.
diagram
=
diagram
;
n
.
documentPoint
=
new
go
.
Point
(
x
,
y
);
n
.
viewPoint
=
diagram
.
transformDocToView
(
n
.
documentPoint
);
n
.
timestamp
=
time
;
n
.
down
=
true
;
this
.
initializeEvent
(
n
,
eventprops
);
diagram
.
lastInput
=
n
;
diagram
.
firstInput
=
n
.
copy
();
diagram
.
currentTool
.
doMouseDown
();
}
/**
* Simulate a mouse move event.
* @param x - the X-coordinate of the mouse point in document coordinates.
* @param y - the Y-coordinate of the mouse point in document coordinates.
* @param time - the timestamp of the simulated event, in milliseconds; default zero
* @param eventprops - an optional argument providing properties for the InputEvent.
*/
mouseMove
(
x
:
number
,
y
:
number
,
time
?:
number
,
eventprops
?:
go
.
ObjectData
):
void
{
if
(
typeof
x
!==
'number'
||
typeof
y
!==
'number'
)
throw
new
Error
(
'Robot.mouseMove first two args must be X,Y numbers'
);
if
(
time
===
undefined
)
time
=
0
;
let
diagram
=
this
.
_diagram
;
if
(
eventprops
&&
(
eventprops
as
any
).
sourceDiagram
)
diagram
=
(
eventprops
as
any
).
sourceDiagram
;
if
(
!
diagram
.
isEnabled
)
return
;
const
n
=
new
go
.
InputEvent
();
n
.
diagram
=
diagram
;
n
.
documentPoint
=
new
go
.
Point
(
x
,
y
);
n
.
viewPoint
=
diagram
.
transformDocToView
(
n
.
documentPoint
);
n
.
timestamp
=
time
;
this
.
initializeEvent
(
n
,
eventprops
);
diagram
.
lastInput
=
n
;
diagram
.
currentTool
.
doMouseMove
();
}
/**
* Simulate a mouse up event.
* @param x - the X-coordinate of the mouse point in document coordinates.
* @param y - the Y-coordinate of the mouse point in document coordinates.
* @param time - the timestamp of the simulated event, in milliseconds; default zero
* @param eventprops - an optional argument providing properties for the InputEvent.
*/
mouseUp
(
x
:
number
,
y
:
number
,
time
?:
number
,
eventprops
?:
go
.
ObjectData
):
void
{
if
(
typeof
x
!==
'number'
||
typeof
y
!==
'number'
)
throw
new
Error
(
'Robot.mouseUp first two args must be X,Y numbers'
);
if
(
time
===
undefined
)
time
=
0
;
let
diagram
=
this
.
_diagram
;
if
(
eventprops
&&
(
eventprops
as
any
).
sourceDiagram
)
diagram
=
(
eventprops
as
any
).
sourceDiagram
;
if
(
!
diagram
.
isEnabled
)
return
;
const
n
:
go
.
InputEvent
=
new
go
.
InputEvent
();
n
.
diagram
=
diagram
;
n
.
documentPoint
=
new
go
.
Point
(
x
,
y
);
n
.
viewPoint
=
diagram
.
transformDocToView
(
n
.
documentPoint
);
n
.
timestamp
=
time
;
n
.
up
=
true
;
if
(
diagram
.
firstInput
.
documentPoint
.
equals
(
n
.
documentPoint
))
n
.
clickCount
=
1
;
// at least??
this
.
initializeEvent
(
n
,
eventprops
);
diagram
.
lastInput
=
n
;
// if (diagram.simulatedMouseUp(null, (n as any).sourceDiagram, n.documentPoint, n.targetDiagram)) return;
diagram
.
currentTool
.
doMouseUp
();
}
/**
* Simulate a mouse wheel event.
* @param delta - non-zero turn
* @param time - the timestamp of the simulated event, in milliseconds; default zero
* @param eventprops - an optional argument providing properties for the InputEvent.
*/
mouseWheel
(
delta
:
number
,
time
?:
number
,
eventprops
?:
go
.
ObjectData
):
void
{
if
(
typeof
delta
!==
'number'
)
throw
new
Error
(
'Robot.mouseWheel first arg must be DELTA number'
);
if
(
time
===
undefined
)
time
=
0
;
const
diagram
=
this
.
_diagram
;
if
(
!
diagram
.
isEnabled
)
return
;
const
n
=
diagram
.
lastInput
.
copy
();
n
.
diagram
=
diagram
;
n
.
delta
=
delta
;
n
.
timestamp
=
time
;
this
.
initializeEvent
(
n
,
eventprops
);
diagram
.
lastInput
=
n
;
diagram
.
currentTool
.
doMouseWheel
();
}
/**
* Simulate a key down event.
* @param keyorcode
* @param time - the timestamp of the simulated event, in milliseconds; default zero
* @param eventprops - an optional argument providing properties for the InputEvent.
*/
keyDown
(
keyorcode
:
string
|
number
,
time
?:
number
,
eventprops
?:
go
.
ObjectData
):
void
{
if
(
typeof
keyorcode
!==
'string'
&&
typeof
keyorcode
!==
'number'
)
throw
new
Error
(
'Robot.keyDown first arg must be a string or a number'
);
if
(
time
===
undefined
)
time
=
0
;
const
diagram
=
this
.
_diagram
;
if
(
!
diagram
.
isEnabled
)
return
;
const
n
=
diagram
.
lastInput
.
copy
();
n
.
diagram
=
diagram
;
if
(
typeof
keyorcode
===
'string'
)
{
n
.
key
=
keyorcode
;
}
else
if
(
typeof
keyorcode
===
'number'
)
{
n
.
key
=
String
.
fromCharCode
(
keyorcode
);
}
n
.
timestamp
=
time
;
n
.
down
=
true
;
this
.
initializeEvent
(
n
,
eventprops
);
diagram
.
lastInput
=
n
;
diagram
.
currentTool
.
doKeyDown
();
}
/**
* Simulate a key up event.
* @param keyorcode
* @param time - the timestamp of the simulated event, in milliseconds; default zero
* @param eventprops - an optional argument providing properties for the InputEvent.
*/
keyUp
(
keyorcode
:
string
|
number
,
time
?:
number
,
eventprops
?:
go
.
ObjectData
):
void
{
if
(
typeof
keyorcode
!==
'string'
&&
typeof
keyorcode
!==
'number'
)
throw
new
Error
(
'Robot.keyUp first arg must be a string or a number'
);
if
(
time
===
undefined
)
time
=
0
;
const
diagram
=
this
.
_diagram
;
if
(
!
diagram
.
isEnabled
)
return
;
const
n
=
diagram
.
lastInput
.
copy
();
n
.
diagram
=
diagram
;
if
(
typeof
keyorcode
===
'string'
)
{
n
.
key
=
keyorcode
;
}
else
if
(
typeof
keyorcode
===
'number'
)
{
n
.
key
=
String
.
fromCharCode
(
keyorcode
);
}
n
.
timestamp
=
time
;
n
.
up
=
true
;
this
.
initializeEvent
(
n
,
eventprops
);
diagram
.
lastInput
=
n
;
diagram
.
currentTool
.
doKeyUp
();
}
}
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