Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
V
vue3-quasar-ts-study01
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
hucy
vue3-quasar-ts-study01
Commits
b54c6275
Commit
b54c6275
authored
Apr 04, 2023
by
hucy
☘
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix:不重要的提交
parent
9a82021a
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
451 additions
and
6 deletions
+451
-6
get-angle.ts
src/common/utils/get-angle.ts
+36
-0
getBoundingBox.ts
src/common/utils/getBoundingBox.ts
+102
-0
index.ts
src/common/utils/index.ts
+2
-0
IndexPage.vue
src/modules/vue-konva/IndexPage.vue
+15
-5
IndexPage2.vue
src/modules/vue-konva/IndexPage2.vue
+295
-0
route.ts
src/modules/vue-konva/route.ts
+1
-1
No files found.
src/common/utils/get-angle.ts
0 → 100644
View file @
b54c6275
/**
* 计算从x1y1到x2y2的直线,与水平线形成的夹角
* 计算规则为顺时针从左侧0°到与该直线形成的夹角
* @param {Object} x1
* @param {Object} y1
* @param {Object} x2
* @param {Object} y2
* @param {Boolean} toAngle 是否转换为角度值,默认false
*/
export
const
getAngle
=
function
(
x1
:
number
,
y1
:
number
,
x2
:
number
,
y2
:
number
,
toAngle
=
false
)
{
const
x
=
x1
-
x2
;
const
y
=
y1
-
y2
;
if
(
!
x
&&
!
y
)
{
return
0
;
}
// 弧度 radian = 角度 * Math.PI / 180
// 角度 angle = 弧度 * 180 / Math.PI
let
res
;
// 角度
const
angle
=
(
180
+
(
Math
.
atan2
(
-
y
,
-
x
)
*
180
)
/
Math
.
PI
+
360
)
%
360
;
res
=
360
-
angle
;
if
(
!
toAngle
)
{
res
=
(
res
*
Math
.
PI
)
/
180
;
}
return
res
;
};
src/common/utils/getBoundingBox.ts
0 → 100644
View file @
b54c6275
import
Decimal
from
'decimal.js'
;
interface
Path
{
x
:
number
;
y
:
number
;
[
proppName
:
string
]:
any
;
}
/**
* 计算2D多边形包围盒
* path: [
* { x: 100, y: 100 },
* { x: 200, y: 100 },
* { x: 200, y: 200 },
* { x: 0, y: 300 },
* ],
* @param {Array} path
*/
export
const
getBoundingBox
=
function
(
path
:
Path
[])
{
let
min_x
=
0
,
min_y
=
0
,
max_x
=
0
,
max_y
=
0
;
const
center
=
{
x
:
0
,
y
:
0
};
let
resPath
:
Path
[]
=
[];
const
length
=
path
.
length
;
let
index
=
0
;
for
(
const
item
of
path
)
{
const
x1
=
item
.
x
;
const
y1
=
item
.
y
;
if
(
index
===
0
)
{
min_x
=
x1
;
min_y
=
y1
;
max_x
=
x1
;
max_y
=
y1
;
path
=
[];
}
else
{
if
(
x1
>
max_x
)
{
max_x
=
x1
;
}
if
(
x1
<
min_x
)
{
min_x
=
x1
;
}
if
(
y1
>
max_y
)
{
max_y
=
y1
;
}
if
(
y1
<
min_y
)
{
min_y
=
y1
;
}
}
index
++
;
}
if
(
length
===
1
)
{
center
.
x
=
min_x
;
center
.
y
=
min_y
;
}
else
if
(
length
>=
2
)
{
if
(
min_x
===
max_x
)
{
// 垂直的线
center
.
x
=
min_x
;
center
.
y
=
Decimal
.
sub
(
max_y
,
min_y
).
div
(
2
).
plus
(
min_y
).
toNumber
();
}
else
if
(
min_y
===
max_y
)
{
// 水平的线
center
.
y
=
min_y
;
center
.
x
=
Decimal
.
sub
(
max_x
,
min_x
).
div
(
2
).
plus
(
min_x
).
toNumber
();
}
else
{
center
.
x
=
Decimal
.
sub
(
max_x
,
min_x
).
div
(
2
).
plus
(
min_x
).
toNumber
();
center
.
y
=
Decimal
.
sub
(
max_y
,
min_y
).
div
(
2
).
plus
(
min_y
).
toNumber
();
const
point1
=
{
x
:
min_x
,
y
:
min_y
,
};
const
point2
=
{
x
:
max_x
,
y
:
min_y
,
};
const
point3
=
{
x
:
max_x
,
y
:
max_y
,
};
const
point4
=
{
x
:
min_x
,
y
:
max_y
,
};
resPath
=
[
point1
,
point2
,
point3
,
point4
];
}
}
return
{
min_x
,
min_y
,
max_x
,
max_y
,
path
:
resPath
,
center
,
};
};
src/common/utils/index.ts
View file @
b54c6275
...
...
@@ -10,6 +10,8 @@ export * from './maths';
export
*
from
'./myCloneDeep'
;
export
*
from
'./get-type'
;
export
*
from
'./is'
;
export
*
from
'./get-angle'
;
export
*
from
'./getBoundingBox'
;
export
{
cloneDeep
,
orderBy
,
...
...
src/modules/vue-konva/IndexPage.vue
View file @
b54c6275
...
...
@@ -73,7 +73,7 @@ onMounted(() => {
state
.
layer
=
new
Konva
.
Layer
();
state
.
stage
.
add
(
state
.
layer
);
for
(
var
i
=
0
;
i
<
3
;
i
++
)
{
for
(
var
i
=
0
;
i
<
10
;
i
++
)
{
state
.
layer
.
add
(
createShape
());
}
...
...
@@ -102,8 +102,8 @@ function createShape() {
y
:
state
.
boundingBox
.
y
,
width
:
state
.
boundingBox
.
width
,
height
:
state
.
boundingBox
.
height
,
stroke
:
'
red
'
,
strokeWidth
:
1
,
stroke
:
'
black
'
,
strokeWidth
:
1
0
,
});
state
.
group
.
add
(
state
.
box
);
return
state
.
group
;
...
...
@@ -156,7 +156,7 @@ function layerDragmove(e: any) {
if
(
group
.
_id
==
target
.
_id
)
{
return
;
}
// r1当前循环的可视矩形区域 r2当前移动目标的可视矩形区域
// r1当前循环
目标
的可视矩形区域 r2当前移动目标的可视矩形区域
let
r1
=
group
.
getClientRect
();
let
r2
=
targetRect
;
let
result
=
haveIntersection
(
r1
,
r2
);
...
...
@@ -165,7 +165,17 @@ function layerDragmove(e: any) {
// 有碰撞
console
.
log
(
'1'
,
target
);
if
(
r2
.
x
<
r1
.
x
+
r1
.
width
/
2
)
{
target
.
x
(
r1
.
x
-
r2
.
width
);
if
(
r2
.
x
+
r2
.
width
<=
r1
.
x
+
r1
.
width
/
2
)
{
// 10边框宽度
target
.
x
(
r1
.
x
-
r2
.
width
+
10
);
}
else
{
if
(
r1
.
y
+
r1
.
height
/
2
>=
r2
.
y
)
{
// 10边框宽度
target
.
y
(
r1
.
y
-
r2
.
height
+
10
);
}
else
if
(
r1
.
y
+
r1
.
height
/
2
<
r2
.
y
)
{
target
.
y
(
r1
.
y
+
r1
.
height
);
}
}
}
else
{
target
.
x
(
r1
.
x
+
r1
.
width
);
}
...
...
src/modules/vue-konva/IndexPage2.vue
0 → 100644
View file @
b54c6275
<!--
* @FileDescription: vue-konva
* @Author: hcy
* @Date: 2023-03-29
-->
<
script
setup
lang=
"ts"
>
import
{
reactive
,
onMounted
}
from
'vue'
;
import
{
getBoundingBox
}
from
'src/common/utils'
;
import
Konva
from
'konva'
;
import
Decimal
from
'decimal.js'
;
const
state
=
reactive
({
stage
:
null
as
any
,
layer
:
null
as
any
,
group
:
null
as
any
,
// shape: null as any,
// boundingBox: null as any,
// box: null as any,
shapePath
:
[
{
name
:
'test1'
,
color
:
'#00D2FF'
,
path
:
[
{
x
:
100
,
y
:
100
},
{
x
:
200
,
y
:
100
},
{
x
:
200
,
y
:
200
},
{
x
:
0
,
y
:
300
},
],
},
{
name
:
'test2'
,
color
:
'#4CAF50'
,
path
:
[
{
x
:
300
,
y
:
200
},
{
x
:
200
,
y
:
400
},
{
x
:
100
,
y
:
600
},
{
x
:
400
,
y
:
600
},
{
x
:
500
,
y
:
200
},
],
},
{
name
:
'test3'
,
color
:
'#FF8A80'
,
path
:
[
{
x
:
600
,
y
:
200
},
{
x
:
500
,
y
:
400
},
{
x
:
300
,
y
:
100
},
],
},
]
as
any
[],
});
const
stageSize
=
reactive
({
width
:
1200
,
height
:
800
,
gridGap
:
100
,
});
onMounted
(()
=>
{
// const hit = Collide2D.collidePointPoint(100, 100, 100, 100);
// console.log('hit', Collide2D);
drawGrid
();
handleData
();
console
.
log
(
'数据'
,
state
.
shapePath
);
state
.
stage
=
new
Konva
.
Stage
({
container
:
'stage-container'
,
width
:
stageSize
.
width
,
height
:
stageSize
.
height
,
});
state
.
layer
=
new
Konva
.
Layer
();
state
.
stage
.
add
(
state
.
layer
);
for
(
const
item
of
state
.
shapePath
)
{
let
shape
=
createShape
(
item
);
if
(
shape
)
{
state
.
layer
.
add
(
shape
);
}
}
state
.
layer
.
on
(
'dragmove'
,
layerDragmove
);
});
function
createShape
(
itemData
:
any
)
{
const
path
=
itemData
.
path
||
[];
const
fillColor
=
itemData
.
color
||
'#000000'
;
const
name
=
itemData
.
name
;
const
boundingBoxPath
=
itemData
.
boundingBox
?.
path
||
[];
if
(
boundingBoxPath
.
length
<
2
)
{
console
.
warn
(
'小于两个点,不能构成多边形,没有边界框'
);
}
else
{
let
group
=
new
Konva
.
Group
({
x
:
boundingBoxPath
[
0
].
x
,
y
:
boundingBoxPath
[
0
].
y
,
draggable
:
true
,
});
// let rectBox = new Konva.Rect({
// x: group.x(),
// y: group.y(),
// width: state.boundingBox.width,
// height: state.boundingBox.height,
// stroke: 'black',
// strokeWidth: 10,
// });
let
shape
:
any
=
new
Konva
.
Shape
({
sceneFunc
:
function
(
context
,
shape
)
{
context
.
beginPath
();
let
index
=
0
;
for
(
const
i
of
path
)
{
const
x
=
i
.
x
;
const
y
=
i
.
y
;
if
(
index
===
0
)
{
context
.
moveTo
(
x
,
y
);
}
else
{
context
.
lineTo
(
x
,
y
);
}
// context.quadraticCurveTo(150, 100, 260, 170); 弧线
index
++
;
}
context
.
closePath
();
// (!) Konva specific method, it is very important
context
.
fillStrokeShape
(
shape
);
},
fill
:
fillColor
,
name
,
// stroke: 'white',
// strokeWidth: 10,
});
group
.
add
(
shape
);
return
group
;
}
}
function
layerDragmove
(
e
:
any
)
{
let
target
=
e
.
target
;
state
.
layer
.
children
.
forEach
(
function
(
group
:
any
)
{
// do not check intersection with itself
// 不检查与自身相交
if
(
group
.
_id
==
target
.
_id
)
{
return
;
}
});
}
function
handleData
()
{
for
(
const
item
of
state
.
shapePath
)
{
item
.
path
=
removeAngleRepeat
(
item
.
path
||
[]);
item
.
boundingBox
=
getBoundingBox
(
item
.
path
||
[]);
}
}
// 一条线上有多个点,只保留起点和终点
function
removeAngleRepeat
(
path
:
any
[])
{
let
length
=
path
.
length
;
if
(
length
>=
2
)
{
let
myMap
=
new
Map
();
let
index
=
1
;
for
(
const
item
of
path
)
{
let
x1
,
y1
,
x2
,
y2
;
if
(
index
<
length
)
{
x1
=
item
.
x
;
y1
=
item
.
y
;
x2
=
path
[
index
].
x
;
y2
=
path
[
index
].
y
;
}
else
{
// 最后一个点连第一个点
x1
=
item
.
x
;
y1
=
item
.
y
;
x2
=
path
[
0
].
x
;
y2
=
path
[
0
].
y
;
}
let
du
=
getAngle
(
x1
,
y1
,
x2
,
y2
,
true
);
if
(
!
myMap
.
has
(
du
))
{
myMap
.
set
(
du
,
item
);
}
// console.log('du', du);
index
++
;
}
let
newArr
:
any
[]
=
[];
for
(
const
value
of
myMap
.
values
())
{
newArr
.
push
(
value
);
}
return
newArr
;
}
else
{
return
path
;
}
}
/**
* 计算从x1y1到x2y2的直线,与水平线形成的夹角
* 计算规则为顺时针从左侧0°到与该直线形成的夹角
* @param {Object} x1
* @param {Object} y1
* @param {Object} x2
* @param {Object} y2
* @param {Boolean} toAngle 是否转换为角度值,默认false
*/
function
getAngle
(
x1
:
number
,
y1
:
number
,
x2
:
number
,
y2
:
number
,
toAngle
=
false
)
{
let
x
=
Decimal
.
sub
(
x1
,
x2
);
let
y
=
Decimal
.
sub
(
y1
,
y2
);
if
(
!
x
.
toNumber
()
&&
!
y
.
toNumber
())
{
return
0
;
}
// 弧度 radian = 角度 * Math.PI / 180
// 角度 angle = 弧度 * 180 / Math.PI
let
res
;
// 角度
// let angle = (180 + (Math.atan2(-y, -x) * 180) / Math.PI + 360) % 360;
let
_atan2
=
Decimal
.
atan2
(
y
.
negated
(),
x
.
negated
());
let
_angle
=
Decimal
.
div
(
Decimal
.
mul
(
_atan2
,
180
),
Math
.
PI
);
let
angle
=
Decimal
.
mod
(
Decimal
.
add
(
180
,
_angle
).
plus
(
360
),
360
);
res
=
Decimal
.
sub
(
360
,
angle
);
if
(
!
toAngle
)
{
res
=
Decimal
.
mul
(
res
,
Math
.
PI
).
div
(
180
);
}
return
res
.
toNumber
();
}
// 网格线
function
drawGrid
()
{
let
canvas
:
any
=
document
.
getElementById
(
'canvas-grid'
);
let
pen
=
canvas
.
getContext
(
'2d'
);
// 绘制网格
const
step
=
stageSize
.
gridGap
;
const
h
=
stageSize
.
height
;
const
w
=
stageSize
.
width
;
const
w_l
=
w
/
step
;
const
h_l
=
h
/
step
;
// 横着的线
for
(
let
i
=
0
;
i
<=
h_l
;
i
++
)
{
pen
.
beginPath
();
pen
.
moveTo
(
0
,
i
*
step
);
pen
.
lineTo
(
w
,
i
*
step
);
pen
.
stroke
();
}
// 竖着的线
for
(
let
i
=
0
;
i
<=
w_l
;
i
++
)
{
pen
.
beginPath
();
pen
.
moveTo
(
i
*
step
,
0
);
pen
.
lineTo
(
i
*
step
,
h
);
pen
.
stroke
();
}
}
</
script
>
<
template
>
<div
class=
"konva-main-page container-height center"
>
<div
class=
"canvas-box"
>
<canvas
id=
"canvas-grid"
:width=
"stageSize.width"
:height=
"stageSize.height"
style=
"position: absolute"
></canvas>
<div
id=
"stage-container"
></div>
</div>
</div>
</
template
>
<
style
lang=
"scss"
scoped
>
.konva-main-page
{
}
.canvas-box
{
box-sizing
:
border-box
;
width
:
1200px
;
height
:
800px
;
border
:
1px
solid
#000
;
background
:
pink
;
}
</
style
>
src/modules/vue-konva/route.ts
View file @
b54c6275
...
...
@@ -2,7 +2,7 @@ export default [
{
path
:
'vue-konva'
,
name
:
'VUE_KONVA'
,
component
:
()
=>
import
(
'./IndexPage.vue'
),
component
:
()
=>
import
(
'./IndexPage
2
.vue'
),
meta
:
{
title
:
'Vue Konva'
,
permission
:
[
'*'
],
...
...
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