Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
lamp
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
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
夜猫
lamp
Commits
5233fb98
Commit
5233fb98
authored
Nov 17, 2022
by
zhushengjie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
彩环修改
parent
82d6e4a9
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
695 additions
and
214 deletions
+695
-214
project.tuya.json
project.tuya.json
+1
-1
index.ts
src/atoms/dpState/index.ts
+21
-0
index.module.less
src/components/hubCircle/index.module.less
+8
-6
index.tsx
src/components/hubCircle/index.tsx
+31
-42
colorBg.png
src/components/hubColorCircle/colorBg.png
+0
-0
colourHeader.tsx
src/components/hubColorCircle/colourHeader.tsx
+195
-0
index.module.css
src/components/hubColorCircle/index.module.css
+0
-11
index.module.less
src/components/hubColorCircle/index.module.less
+146
-10
index.tsx
src/components/hubColorCircle/index.tsx
+286
-137
index.module.less
src/pages/home/index.module.less
+7
-7
No files found.
project.tuya.json
View file @
5233fb98
...
...
@@ -10,5 +10,5 @@
"DeviceKit"
:
"2.4.7"
},
"baseversion"
:
"2.9.5"
,
"productId"
:
"
qton0thk3uxf77hv
"
"productId"
:
"
hewd8dsaiwxpznpr
"
}
src/atoms/dpState/index.ts
View file @
5233fb98
...
...
@@ -17,8 +17,19 @@ export interface DpState {
do_not_disturb
:
boolean
;
}
export
interface
ColorData
{
// mouseMoveX: number;
// mouseMoveY: number;
// locationX: number;
// locationY: number;
ifDrag
:
boolean
;
}
type
UpdateDpStatePayload
=
Partial
<
DpState
>
;
type
UpdateColorDataPayload
=
Partial
<
ColorData
>
;
/**
* 定义一个 dpStateAtom
*
...
...
@@ -34,6 +45,10 @@ export const dpStateAtom = atom<DpState, UpdateDpStatePayload>(null, (get, set,
set
(
dpStateAtom
,
{
...(
get
(
dpStateAtom
)
||
{}),
...
payload
});
});
export
const
colorDataAtom
=
atom
<
ColorData
,
UpdateColorDataPayload
>
(
null
,
(
get
,
set
,
payload
)
=>
{
set
(
colorDataAtom
,
{
...(
get
(
colorDataAtom
)
||
{}),
...
payload
});
});
/**
* 定义一个基于 dpStateAtom 的选择器
*
...
...
@@ -47,3 +62,9 @@ export const dpStateAtom = atom<DpState, UpdateDpStatePayload>(null, (get, set,
* @docs 详见 https://jotai.org/docs/utils/select-atom
*/
export
const
selectDpStateAtom
=
selectAtom
<
DpState
,
DpState
>
(
dpStateAtom
,
data
=>
data
,
deepEqual
);
export
const
selectColorDataAtom
=
selectAtom
<
ColorData
,
ColorData
>
(
colorDataAtom
,
data
=>
data
,
deepEqual
);
src/components/hubCircle/index.module.less
View file @
5233fb98
...
...
@@ -6,15 +6,17 @@
.header {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
//
display: flex;
//
justify-content: center;
//
align-items: center;
.circleContent {
position: relative;
z-index: 30;
left: 100px;
top: 50px;
background-image: url(./tempBg.png);
border:none;
border:
none;
.circle {
position: absolute;
...
...
@@ -22,12 +24,12 @@
left: 0;
top: 0;
border-radius: 50%;
border: 10
r
px solid #ffffff;
border: 10px solid #ffffff;
display: flex;
justify-content: center;
align-items: center;
color: #ffffff;
font-size:
40r
px;
font-size:
20
px;
-webkit-user-select: none;
}
...
...
src/components/hubCircle/index.tsx
View file @
5233fb98
...
...
@@ -14,7 +14,7 @@ const HubCircle: React.FC<Props> = props => {
const
{
hsv2rgb
,
rgb2hex
}
=
utils
;
// document.getElementById;
const
dataSourse
=
{
num
:
0
,
isDrag
:
false
,
angleLimit
:
135
,
// 角度限制
angleValue
:
0
,
// 角度信息 0 ~ 360
...
...
@@ -23,29 +23,29 @@ const HubCircle: React.FC<Props> = props => {
containerWidth
:
400
,
containerStyle
:
{
width
:
'
400r
px'
,
height
:
'
400r
px'
,
backgroundSize
:
'
400rpx 400r
px'
,
width
:
'
200
px'
,
height
:
'
200
px'
,
backgroundSize
:
'
200px 200
px'
,
},
circleStyle
:
{
width
:
'
200r
px'
,
height
:
'
200r
px'
,
left
:
'
100r
px'
,
top
:
'
100r
px'
,
width
:
'
100
px'
,
height
:
'
100
px'
,
left
:
'
50
px'
,
top
:
'
50
px'
,
},
containerOffset
:
{
// 容器位置
x
:
100
,
y
:
1
0
0
,
y
:
1
5
0
,
},
mouse_offset
:
{
x
:
0
,
y
:
0
},
circle_r
:
2
00
,
// 圆形外半径(容器宽度/2)
circle_b
:
84
,
// 圆形边距
bar_r
:
42
,
// 小球半径(圆形边距/2)
circle_r
:
1
00
,
// 圆形外半径(容器宽度/2)
circle_b
:
42
,
// 圆形边距
bar_r
:
21
,
// 小球半径(圆形边距/2)
};
const
[
addFlag
,
setAddFlag
]
=
useState
(
true
);
...
...
@@ -56,8 +56,6 @@ const HubCircle: React.FC<Props> = props => {
{
temp_value
:
300
,
bright_value
:
300
,
color
:
'#FFE2A4'
,
active
:
false
},
]);
const
[
isDrag
,
setIsDrag
]
=
useState
(
false
);
const
[
dataState
,
setDataState
]
=
useState
({
angleValue
:
0
,
// 角度值 0 ~ 360
angleShow
:
0
,
// 角度展示 0 ~ 180
...
...
@@ -67,7 +65,7 @@ const HubCircle: React.FC<Props> = props => {
const
[
circleLocation
,
setCircleLocation
]
=
useState
({
// 小球位置
left
:
158
,
left
:
79
,
top
:
0
,
});
...
...
@@ -85,15 +83,6 @@ const HubCircle: React.FC<Props> = props => {
const
handleCirleClick
=
(
e
:
any
,
item
:
colorItem
):
void
=>
{
e
.
origin
.
stopPropagation
();
if
(
dataSourse
.
num
===
0
)
{
// 获取容器位置 (无法操作DOM,暂时通过初次计算获取)
dataSourse
.
num
=
1
;
const
X
=
e
.
touches
[
0
].
pageX
+
dataSourse
.
bar_r
-
dataSourse
.
containerWidth
/
2
;
const
Y
=
e
.
touches
[
0
].
pageY
;
dataSourse
.
containerOffset
.
x
=
X
;
dataSourse
.
containerOffset
.
y
=
Y
;
}
const
index
=
colorArr
.
findIndex
(
el
=>
{
return
item
.
bright_value
===
el
.
bright_value
&&
el
.
temp_value
===
item
.
temp_value
;
});
...
...
@@ -132,8 +121,6 @@ const HubCircle: React.FC<Props> = props => {
const
color
=
hsv2rgb
(
h
,
s
,
v
);
const
nowColor
=
rgb2hex
(
color
[
0
],
color
[
1
],
color
[
2
]);
console
.
log
(
nowColor
);
setDataState
({
...
dataState
,
nowColor
,
...
...
@@ -165,12 +152,13 @@ const HubCircle: React.FC<Props> = props => {
const
mouse_offset_x
=
e
.
origin
.
touches
[
0
].
clientX
-
dataSourse
.
containerOffset
.
x
-
e
.
origin
.
currentT
arget
.
offsetLeft
-
e
.
origin
.
t
arget
.
offsetLeft
-
dataSourse
.
bar_r
;
const
mouse_offset_y
=
-
(
e
.
origin
.
touches
[
0
].
clientY
-
dataSourse
.
containerOffset
.
y
-
e
.
origin
.
currentT
arget
.
offsetTop
-
e
.
origin
.
t
arget
.
offsetTop
-
dataSourse
.
bar_r
);
dataSourse
.
mouse_offset
.
x
=
mouse_offset_x
;
...
...
@@ -200,7 +188,7 @@ const HubCircle: React.FC<Props> = props => {
updateContent
(
radian
);
if
(
!
isDrag
)
{
if
(
!
dataSourse
.
isDrag
)
{
return
;
}
setCircleLocation
({
...
...
@@ -223,9 +211,18 @@ const HubCircle: React.FC<Props> = props => {
// 0 ~ 180
const
angleShow
=
angleValue
>
180
?
360
-
angleValue
:
angleValue
;
const
{
angleLimit
}
=
dataSourse
;
if
(
angleShow
>
angleLimit
)
{
dataSourse
.
isDrag
=
false
;
return
;
}
if
(
!
dataSourse
.
isDrag
)
{
dataSourse
.
isDrag
=
true
;
}
const
tempStart
=
dataSourse
.
tempValue
[
0
];
const
tempEnd
=
dataSourse
.
tempValue
[
1
];
const
{
angleLimit
}
=
dataSourse
;
let
tempshow
=
(
tempEnd
-
tempStart
)
/
2
+
tempStart
;
// 中间值 角度对应0
if
(
angleValue
<
180
)
{
...
...
@@ -236,14 +233,6 @@ const HubCircle: React.FC<Props> = props => {
tempshow
-=
((
tempEnd
-
tempshow
)
/
angleLimit
)
*
angleShow
;
}
if
(
angleShow
>
angleLimit
)
{
setIsDrag
(
false
);
return
;
}
if
(
!
isDrag
)
{
setIsDrag
(
true
);
}
tempshow
=
Math
.
floor
(
tempshow
);
setDataState
({
...
...
@@ -264,10 +253,10 @@ const HubCircle: React.FC<Props> = props => {
<
View
className=
{
styles
.
circleBar
}
style=
{
{
left
:
`${circleLocation.left}
r
px`
,
top
:
`${circleLocation.top}
r
px`
,
width
:
`${dataSourse.bar_r * 2}
r
px`
,
height
:
`${dataSourse.bar_r * 2}
r
px`
,
left
:
`${circleLocation.left}px`
,
top
:
`${circleLocation.top}px`
,
width
:
`${dataSourse.bar_r * 2}px`
,
height
:
`${dataSourse.bar_r * 2}px`
,
}
}
onTouchStart=
{
handleBarTouch
}
onTouchMove=
{
handleBarMove
}
...
...
src/components/hubColorCircle/colorBg.png
0 → 100644
View file @
5233fb98
214 KB
src/components/hubColorCircle/colourHeader.tsx
0 → 100644
View file @
5233fb98
import
React
,
{
useState
,
useCallback
}
from
'react'
;
import
{
utils
}
from
'@ray-js/panel-sdk'
;
import
{
useAtomValue
,
useSetAtom
}
from
'jotai'
;
import
{
ColorData
,
colorDataAtom
,
selectColorDataAtom
}
from
'@/atoms'
;
import
{
View
,
Text
,
Slider
,
Image
,
usePageEvent
}
from
'@ray-js/ray'
;
import
styles
from
'./index.module.less'
;
import
{
Props
}
from
'./index.type'
;
import
imgs
from
'../../res'
;
const
{
hsv2rgbString
}
=
utils
;
// 平移法
const
HubColorCircle
:
React
.
FC
<
Props
>
=
props
=>
{
const
dpState
=
props
.
DpStateData
;
const
codeMap
=
props
.
DpCodesMap
;
const
setColorStateAtom
=
useSetAtom
(
colorDataAtom
);
const
colorStateInAtom
=
useAtomValue
(
selectColorDataAtom
);
const
data
=
{
radius
:
135
,
// 容器半径
innerRadius
:
76
,
// 内半径
thumbRadius
:
27.5
,
// 圆球半径
thumbInnerRadius
:
22.5
,
// 圆球内环
ringSize
:
135
-
76
,
// 圆环尺寸
colorThumRadius
:
76
-
5
,
cx
:
135
-
27.5
,
// 圆心相对父容器位置
cy
:
135
-
27.5
,
// 圆心相对父容器位置
fixedLength
:
135
-
(
135
-
76
)
*
0.5
,
// 可拖动圆球至原点的固定距离(令圆球始终在在色环中居中)
containerOffsetX
:
135
-
27.5
,
containerOffsetY
:
(
135
-
76
)
*
0.5
-
27.5
*
0.5
,
mouseMove
:
{
// 父元素偏移
x
:
0
,
y
:
0
,
},
location
:
{
// 点击时的小球位置
x
:
0
,
y
:
0
,
},
disabled
:
false
,
RingBackground
:
imgs
.
colorBg
,
hue
:
90
,
// 色相
};
const
atomState
=
{
// 父元素偏移
mouseMoveX
:
0
,
mouseMoveY
:
0
,
// 点击时的小球位置
locationX
:
0
,
locationY
:
0
,
};
const
hueToColor
=
hue
=>
{
return
hsv2rgbString
(
hue
,
1000
,
1000
);
};
const
[
translateX
,
setTranslateX
]
=
useState
(
0
);
const
[
translateY
,
setTranslateY
]
=
useState
(
0
);
const
[
nowColor
,
setNowColor
]
=
useState
(
hueToColor
(
data
.
hue
));
const
[
hueState
,
sethueState
]
=
useState
(
data
.
hue
);
const
getCoordByHue
=
(
hue
:
number
)
=>
{
const
rad
=
((
360
-
hue
)
*
Math
.
PI
)
/
180
;
const
x
=
data
.
cx
+
data
.
fixedLength
*
Math
.
cos
(
rad
);
const
y
=
data
.
cy
+
data
.
fixedLength
*
Math
.
sin
(
rad
);
return
{
x
,
y
};
};
const
handleBarTouch
=
e
=>
{
atomState
.
locationX
=
e
.
origin
.
currentTarget
.
offsetLeft
;
atomState
.
locationY
=
e
.
origin
.
currentTarget
.
offsetTop
;
setColorStateAtom
(
atomState
);
console
.
log
(
data
.
location
,
'touch'
);
atomState
.
mouseMoveX
=
e
.
origin
.
currentTarget
.
offsetLeft
;
atomState
.
mouseMoveY
=
e
.
origin
.
currentTarget
.
offsetTop
;
};
const
getHueByCoord
=
(
dx
:
number
,
dy
:
number
)
=>
{
// 0 ~ 2π
const
rad
=
getRadianByCoord
(
dx
,
dy
);
return
(
rad
*
180
)
/
Math
.
PI
;
};
const
getRadianByCoord
=
(
dx
:
number
,
dy
:
number
)
=>
{
const
{
thumbRadius
}
=
data
;
// 相对中心点的坐标
const
xCenter
=
dx
-
data
.
cx
-
thumbRadius
;
const
yCenter
=
dy
-
data
.
cy
-
thumbRadius
;
let
rad
=
Math
.
atan2
(
yCenter
,
xCenter
);
if
(
xCenter
>
0
&&
yCenter
>
0
)
rad
=
Math
.
PI
*
2
-
rad
;
if
(
xCenter
<
0
&&
yCenter
>
0
)
rad
=
Math
.
PI
*
2
-
rad
;
if
(
xCenter
<
0
&&
yCenter
<
0
)
rad
=
Math
.
abs
(
rad
);
if
(
xCenter
>
0
&&
yCenter
<
0
)
rad
=
Math
.
abs
(
rad
);
if
(
xCenter
===
0
&&
yCenter
>
0
)
rad
=
(
Math
.
PI
*
3
)
/
2
;
if
(
xCenter
===
0
&&
yCenter
<
0
)
rad
=
Math
.
PI
/
2
;
return
rad
;
};
const
handleMove
=
e
=>
{
// 最近一次的移动路程,dx的正负决定了移动的正负
const
{
locationX
,
locationY
}
=
colorStateInAtom
;
const
dx
=
e
.
origin
.
touches
[
0
].
clientX
-
locationX
;
const
dy
=
e
.
origin
.
touches
[
0
].
clientY
-
locationY
;
const
hue
=
Math
.
round
(
getHueByCoord
(
dx
,
dy
));
const
{
x
=
0
,
y
=
0
}
=
getCoordByHue
(
hue
);
const
color
=
hueToColor
(
hue
);
setTranslateX
(
x
);
setTranslateY
(
y
);
setNowColor
(
color
);
sethueState
(
hue
);
};
return
(
<
View
className=
{
styles
.
header
}
>
<
View
className=
{
styles
.
circleContent
}
style=
{
{
width
:
`${data.radius * 2}px`
,
height
:
`${data.radius * 2}px`
}
}
>
{
/* 圆环 */
}
<
View
className=
{
styles
.
sectionRing
}
style=
{
{
width
:
`${data.radius * 2}px`
,
height
:
`${data.radius * 2}px`
}
}
>
<
Image
style=
{
{
width
:
`${data.radius * 2}px`
,
height
:
`${data.radius * 2}px`
,
borderRadius
:
'50%'
,
}
}
src=
{
imgs
.
colorBg
}
/>
</
View
>
{
/* 圆环中间色彩值 */
}
<
View
className=
{
styles
.
colorThum
}
style=
{
{
position
:
'absolute'
,
left
:
`${data.radius - data.colorThumRadius}px`
,
top
:
`${data.radius - data.colorThumRadius}px`
,
width
:
`${data.colorThumRadius * 2}px`
,
height
:
`${data.colorThumRadius * 2}px`
,
borderRadius
:
'50%'
,
backgroundColor
:
nowColor
,
}
}
>
Angle:
{
hueState
}
°
</
View
>
{
/* 圆球 */
}
<
View
className=
{
styles
.
bar
}
style=
{
{
top
:
`${data.containerOffsetY}px`
,
left
:
`${data.containerOffsetX}px`
,
width
:
`${data.thumbRadius * 2}px`
,
height
:
`${data.thumbRadius * 2}px`
,
borderRadius
:
'50%'
,
opacity
:
1
,
transform
:
`translateX(${translateX}px) translateY(${translateY}px)`
,
}
}
onTouchStart=
{
handleBarTouch
}
onTouchMove=
{
handleMove
}
>
<
View
style=
{
{
width
:
`${data.thumbInnerRadius * 2}px`
,
height
:
`${data.thumbInnerRadius * 2}px`
,
borderRadius
:
'50%'
,
backgroundColor
:
nowColor
,
}
}
/>
</
View
>
</
View
>
</
View
>
);
};
export
default
HubColorCircle
;
src/components/hubColorCircle/index.module.css
deleted
100644 → 0
View file @
82d6e4a9
.sectionRing
{
align-items
:
center
;
justify-content
:
center
;
}
.bar
{
position
:
absolute
;
align-items
:
center
;
justify-content
:
center
;
background-color
:
'#fff'
;
box-shadow
:
0
5
rpx
12
rpx
rgba
(
0
,
0
,
0
,
0.6
);
}
src/components/hubColorCircle/index.module.less
View file @
5233fb98
.sectionRing {
align-items: center;
justify-content: center;
}
.bar {
position: absolute;
align-items: center;
justify-content: center;
background-color: '#fff';
box-shadow: 0 5rpx 12rpx rgba(0, 0, 0, 0.6);
.box {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
.header {
flex: 1;
// display: flex;
// justify-content: center;
// align-items: center;
.circleContent {
position: relative;
z-index: 30;
left: 100px;
top: 50px;
background-image: url(./colorBg.png);
border: none;
.circle {
position: absolute;
z-index: 10;
left: 0;
top: 0;
border-radius: 50%;
border: 10px solid #ffffff;
display: flex;
justify-content: center;
align-items: center;
color: #ffffff;
font-size: 20px;
-webkit-user-select: none;
}
.circleBar {
position: absolute;
z-index: 50;
border-radius: 50%;
background-color: transparent;
border: 4rpx solid rgba(255, 255, 255, 1);
cursor: pointer;
box-shadow: 0 5rpx 12rpx rgba(0, 0, 0, 0.6);
}
}
}
.panel {
.configList {
margin-bottom: 50rpx;
display: flex;
justify-content: center;
align-items: center;
.cutBar {
color: red;
font-size: 24rpx;
}
.addStyle {
color: white;
font-size: 24rpx;
}
.icoImg {
width: 30rpx;
height: 30rpx;
}
.slider {
width: 500rpx;
}
.SliderValue {
color: #fff;
font-size: 16rpx;
width: 20rpx;
}
.colorCircle {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
border: 1rpx solid #fff;
}
.colorCircle:nth-child(n + 1) {
margin-left: 15rpx;
}
.cutBar {
color: red;
}
.addBar {
color: #fff;
}
}
}
.circleContent {
width: 200rpx;
height: 200rpx;
border: 1rpx solid #000;
}
.circleBar {
width: 200rpx;
height: 200rpx;
}
}
// .header {
// display: flex;
// // align-items: center;
// // justify-content: center;
// }
// .circleContent {
// position: relative;
// }
// .sectionRing {
// display: flex;
// align-items: center;
// justify-content: center;
// }
// .bar {
// display: flex;
// position: absolute;
// align-items: center;
// justify-content: center;
// background-color: '#fff';
// box-shadow: 0 5rpx 12rpx rgba(0, 0, 0, 0.6);
// }
// .colorThum {
// display: flex;
// position: absolute;
// align-items: center;
// color: white;
// font-size: 16px;
// font-weight: 700;
// }
src/components/hubColorCircle/index.tsx
View file @
5233fb98
import
React
,
{
useState
,
useCallback
}
from
'react'
;
import
React
,
{
useState
}
from
'react'
;
import
{
utils
}
from
'@ray-js/panel-sdk'
;
import
{
getElementById
}
from
'@ray-js/api'
;
import
{
View
,
Text
,
Slider
,
Image
,
usePageEvent
}
from
'@ray-js/ray'
;
import
{
useAtomValue
,
useSetAtom
}
from
'jotai'
;
import
{
ColorData
,
colorDataAtom
,
selectColorDataAtom
}
from
'@/atoms'
;
import
{
View
,
Text
,
Slider
,
Image
}
from
'@ray-js/ray'
;
import
styles
from
'./index.module.less'
;
import
{
Props
}
from
'./index.type'
;
import
imgs
from
'../../res'
;
const
{
hsv2rgbString
}
=
utils
;
type
colorItem
=
Record
<
string
,
any
>
;
// onStartShouldSetPanResponder: this.handleSetResponder, 判断是否按中滑块
// onMoveShouldSetPanResponder: () => this.locked,
// onPanResponderGrant: this.handleGrant,
// onPanResponderMove: this.handleMove, 开始移动
// onPanResponderRelease: this.handleRelease, 完成一个手势操作
const
HubColorCircle
:
React
.
FC
<
Props
>
=
props
=>
{
const
HubCircle
:
React
.
FC
<
Props
>
=
props
=>
{
const
dpState
=
props
.
DpStateData
;
const
codeMap
=
props
.
DpCodesMap
;
const
data
=
{
radius
:
135
,
innerRadius
:
76
,
// 内半径
thumbRadius
:
27.5
,
// 圆球半径
thumbInnerRadius
:
22.5
,
// 圆球内环
ringSize
:
135
-
76
,
// 圆环尺寸
cx
:
135
-
27.5
,
cy
:
135
-
27.5
,
const
setColorStateAtom
=
useSetAtom
(
colorDataAtom
);
const
colorStateInAtom
=
useAtomValue
(
selectColorDataAtom
);
const
{
hsv2rgb
,
rgb2hex
,
hsv2rgbString
}
=
utils
;
// document.getElementById;
const
dataSourse
=
{
containerWidth
:
400
,
fixedLength
:
135
-
(
135
-
76
)
*
0.5
,
// 可拖动圆球至原点的固定距离(令圆球始终在在色环中居中)
containerStyle
:
{
width
:
'200px'
,
height
:
'200px'
,
backgroundSize
:
'200px 200px'
,
},
containerOffset
:
{
// 容器位置
x
:
0
,
y
:
0
,
x
:
10
0
,
y
:
15
0
,
},
mouseMove
:
{
// 父元素偏移
x
:
0
,
y
:
0
,
},
mouse_offset
:
{
x
:
0
,
y
:
0
},
location
:
{
// 点击时的小球位置
x
:
0
,
y
:
0
,
},
circle_r
:
100
,
// 圆形外半径(容器宽度/2)
circle_b
:
42
,
// 圆形边距
bar_r
:
21
,
// 小球半径(圆形边距/2)
hue
:
270
,
};
const
hueToColor
=
(
h
:
number
,
s
=
100
,
v
=
100
,
a
=
1
)
=>
{
return
hsv2rgbString
(
h
,
s
,
v
,
a
);
};
const
[
addFlag
,
setAddFlag
]
=
useState
(
true
);
const
[
colorArr
,
setColorArr
]
=
useState
<
colorItem
[]
>
([
{
hue
:
0
,
temp_value
:
1000
,
bright_value
:
1000
,
color
:
hueToColor
(
0
),
active
:
false
},
{
hue
:
90
,
temp_value
:
1000
,
bright_value
:
1000
,
color
:
hueToColor
(
90
),
active
:
false
},
{
hue
:
180
,
temp_value
:
1000
,
bright_value
:
1000
,
color
:
hueToColor
(
180
),
active
:
false
},
]);
const
[
dataState
,
setDataState
]
=
useState
({
hue
:
90
,
// 角度展示 0 ~ 180
temp_value
:
500
,
bright_value
:
500
,
nowColor
:
hueToColor
(
90
),
// 当前颜色
});
const
[
circleLocation
,
setCircleLocation
]
=
useState
({
// 小球位置
left
:
79
,
top
:
0
,
});
const
toParseInt
=
(
value
:
number
):
number
=>
{
return
Math
.
floor
(
value
);
};
const
handleCirleClick
=
(
e
:
any
,
item
:
colorItem
):
void
=>
{
e
.
origin
.
stopPropagation
();
const
index
=
colorArr
.
findIndex
(
el
=>
{
return
(
item
.
hue
===
el
.
hue
&&
item
.
bright_value
===
el
.
bright_value
&&
el
.
temp_value
===
item
.
temp_value
);
});
disabled
:
false
,
RingBackground
:
imgs
.
colorBg
,
hue
:
0
,
// 色相
if
(
item
.
active
)
{
colorArr
.
splice
(
index
,
1
);
if
(
colorArr
.
length
<
6
)
{
setAddFlag
(
true
);
}
}
else
{
for
(
let
i
=
0
;
i
<
colorArr
.
length
;
i
++
)
{
colorArr
[
i
].
active
=
false
;
}
colorArr
[
index
].
active
=
true
;
}
const
value
=
[...
colorArr
];
setColorArr
(
value
);
};
const
hueToColor
=
hue
=>
{
return
hsv2rgbString
(
hue
,
1000
,
1000
);
const
handleCircleAdd
=
()
=>
{
if
(
colorArr
.
length
>
5
)
{
setAddFlag
(
false
);
return
;
}
const
h
=
dataState
.
hue
;
const
nowColor
=
hueToColor
(
h
,
dataState
.
temp_value
/
10
,
dataState
.
bright_value
/
9.9
);
setDataState
({
...
dataState
,
nowColor
,
});
const
item
=
{
hue
:
h
,
temp_value
:
dataState
.
temp_value
,
bright_value
:
dataState
.
bright_value
,
color
:
nowColor
,
active
:
false
,
};
const
flag
=
colorArr
.
some
((
el
:
colorItem
)
=>
{
return
(
item
.
hue
===
el
.
hue
&&
item
.
bright_value
===
el
.
bright_value
&&
item
.
temp_value
===
el
.
temp_value
);
});
if
(
flag
)
{
// setAddFlag(true);
return
;
}
colorArr
.
push
(
item
);
const
value
=
[...
colorArr
];
setColorArr
(
value
);
};
const
[
translateX
,
setTranslateX
]
=
useState
(
0
);
const
[
translateY
,
setTranslateY
]
=
useState
(
0
);
const
[
nowColor
,
setNowColor
]
=
useState
(
hueToColor
(
data
.
hue
));
const
handleBarTouch
=
(
e
:
any
)
=>
{
e
.
origin
.
stopPropagation
();
setColorStateAtom
({
ifDrag
:
true
});
// 移动距离:小球的坐标位置-容器的偏移位置-小球相对容器的偏移位置-小球半径
const
mouse_offset_x
=
e
.
origin
.
touches
[
0
].
clientX
-
dataSourse
.
containerOffset
.
x
-
e
.
origin
.
target
.
offsetLeft
-
dataSourse
.
bar_r
;
const
getCoordByHue
=
(
hue
:
number
)
=>
{
const
rad
=
((
360
-
hue
)
*
Math
.
PI
)
/
180
;
const
x
=
data
.
cx
+
data
.
fixedLength
*
Math
.
cos
(
rad
);
const
y
=
data
.
cy
+
data
.
fixedLength
*
Math
.
sin
(
rad
);
return
{
x
,
y
};
const
mouse_offset_y
=
-
(
e
.
origin
.
touches
[
0
].
clientY
-
dataSourse
.
containerOffset
.
y
-
e
.
origin
.
target
.
offsetTop
-
dataSourse
.
bar_r
);
dataSourse
.
mouse_offset
.
x
=
mouse_offset_x
;
dataSourse
.
mouse_offset
.
y
=
mouse_offset_y
;
};
const
handleBarTouch
=
e
=>
{
data
.
location
.
x
=
e
.
origin
.
touches
[
0
].
clientX
;
data
.
location
.
y
=
e
.
origin
.
touches
[
0
].
clientY
;
data
.
mouseMove
.
x
=
e
.
origin
.
currentTarget
.
offsetLeft
;
data
.
mouseMove
.
y
=
e
.
origin
.
currentTarget
.
offsetTop
;
const
handleBarMove
=
(
e
:
any
)
=>
{
e
.
origin
.
stopPropagation
();
const
event_offset_x
=
e
.
origin
.
touches
[
0
].
clientX
-
dataSourse
.
mouse_offset
.
x
-
dataSourse
.
containerOffset
.
x
-
dataSourse
.
circle_r
;
const
event_offset_y
=
-
(
e
.
origin
.
touches
[
0
].
clientY
-
dataSourse
.
mouse_offset
.
y
-
dataSourse
.
containerOffset
.
y
-
dataSourse
.
circle_r
);
const
radian
=
Math
.
atan2
(
event_offset_y
,
event_offset_x
);
const
x
=
Math
.
cos
(
radian
)
*
(
dataSourse
.
circle_r
-
dataSourse
.
circle_b
/
2
);
const
y
=
Math
.
sin
(
radian
)
*
(
dataSourse
.
circle_r
-
dataSourse
.
circle_b
/
2
);
const
left
=
x
-
dataSourse
.
bar_r
+
dataSourse
.
circle_r
;
const
top
=
dataSourse
.
circle_r
-
(
y
+
dataSourse
.
bar_r
);
if
(
!
colorStateInAtom
.
ifDrag
)
{
return
;
}
updateContent
(
radian
);
setCircleLocation
({
...
circleLocation
,
left
,
top
,
});
};
const
getHueByCoord
=
(
dx
:
number
,
dy
:
number
)
=>
{
// 0 ~ 2π
const
rad
=
getRadianByCoord
(
dx
,
dy
);
return
(
rad
*
180
)
/
Math
.
PI
;
const
updateContent
=
(
radian
:
number
)
=>
{
let
angle
=
radian
*
(
180
/
Math
.
PI
);
// -180 ~ 180
if
(
angle
>=
-
180
&&
angle
<=
90
)
{
angle
=
90
-
angle
;
}
else
{
angle
=
360
-
(
angle
-
90
);
}
// 0 ~ 360
// 转为逆时针顺序
let
hue
=
Math
.
floor
(
360
-
angle
+
90
);
if
(
hue
>=
360
)
{
hue
-=
360
;
}
const
nowColor
=
hueToColor
(
hue
,
dataState
.
temp_value
/
10
,
dataState
.
bright_value
/
9.9
);
setDataState
({
...
dataState
,
hue
,
nowColor
,
});
};
const
getRadianByCoord
=
(
dx
:
number
,
dy
:
number
)
=>
{
const
{
thumbRadius
}
=
data
;
const
xCenter
=
dx
-
data
.
cx
-
thumbRadius
;
const
yCenter
=
dy
-
data
.
cy
-
thumbRadius
;
let
rad
=
Math
.
atan2
(
yCenter
,
xCenter
);
if
(
xCenter
>
0
&&
yCenter
>
0
)
rad
=
Math
.
PI
*
2
-
rad
;
if
(
xCenter
<
0
&&
yCenter
>
0
)
rad
=
Math
.
PI
*
2
-
rad
;
if
(
xCenter
<
0
&&
yCenter
<
0
)
rad
=
Math
.
abs
(
rad
);
if
(
xCenter
>
0
&&
yCenter
<
0
)
rad
=
Math
.
abs
(
rad
);
if
(
xCenter
===
0
&&
yCenter
>
0
)
rad
=
(
Math
.
PI
*
3
)
/
2
;
if
(
xCenter
===
0
&&
yCenter
<
0
)
rad
=
Math
.
PI
/
2
;
return
rad
;
const
handleStateChange
=
(
type
,
e
)
=>
{
if
(
type
===
'temp_value'
)
{
const
temp_value
=
e
.
value
;
const
nowColor
=
hueToColor
(
dataState
.
hue
,
temp_value
/
10
,
dataState
.
bright_value
/
9.9
);
setDataState
({
...
dataState
,
temp_value
,
nowColor
,
});
}
if
(
type
===
'bright_value'
)
{
const
bright_value
=
e
.
value
;
const
nowColor
=
hueToColor
(
dataState
.
hue
,
dataState
.
temp_value
/
10
,
bright_value
/
9.9
);
setDataState
({
...
dataState
,
bright_value
,
nowColor
,
});
}
};
const
handleMove
=
e
=>
{
// 最近一次的移动路程
const
dx
=
e
.
origin
.
touches
[
0
].
clientX
-
data
.
location
.
x
;
const
dy
=
e
.
origin
.
touches
[
0
].
clientY
-
data
.
location
.
y
;
const
hue
=
Math
.
round
(
getHueByCoord
(
dx
,
dy
));
const
{
x
=
0
,
y
=
0
}
=
getCoordByHue
(
hue
);
const
color
=
hueToColor
(
hue
);
setTranslateX
(
x
);
setTranslateY
(
y
);
setNowColor
(
color
);
const
handleBarEnd
=
()
=>
{
setColorStateAtom
({
ifDrag
:
false
});
};
return
(
<
View
className=
{
styles
.
box
}
style=
{
{
width
:
data
.
radius
*
2
,
height
:
data
.
radius
*
2
}
}
>
{
/* 圆环 */
}
<
View
className=
{
styles
.
sectionRing
}
style=
{
{
width
:
data
.
radius
*
2
,
height
:
data
.
radius
*
2
}
}
>
<
Image
style=
{
{
width
:
data
.
radius
*
2
,
height
:
data
.
radius
*
2
,
borderRadius
:
data
.
radius
,
}
}
src=
{
imgs
.
colorBg
}
/>
<
View
className=
{
styles
.
box
}
>
<
View
className=
{
styles
.
header
}
>
<
View
className=
{
styles
.
circleContent
}
id=
"circleContent"
style=
{
dataSourse
.
containerStyle
}
>
<
View
className=
{
styles
.
circle
}
style=
{
{
width
:
'100px'
,
height
:
'100px'
,
left
:
'50px'
,
top
:
'50px'
,
backgroundColor
:
dataState
.
nowColor
,
}
}
>
{
dataState
.
hue
}
°
</
View
>
<
View
className=
{
styles
.
circleBar
}
style=
{
{
left
:
`${circleLocation.left}px`
,
top
:
`${circleLocation.top}px`
,
width
:
`${dataSourse.bar_r * 2}px`
,
height
:
`${dataSourse.bar_r * 2}px`
,
}
}
onTouchStart=
{
handleBarTouch
}
onTouchMove=
{
handleBarMove
}
onTouchEnd=
{
handleBarEnd
}
/>
</
View
>
</
View
>
{
/* 圆球 */
}
<
View
className=
{
styles
.
bar
}
style=
{
{
width
:
data
.
thumbRadius
*
2
,
height
:
data
.
thumbRadius
*
2
,
borderRadius
:
data
.
thumbRadius
,
opacity
:
1
,
transform
:
`translateX(${translateX}) translateY(${translateY})`
,
}
}
onTouchStart=
{
handleBarTouch
}
onTouchMove=
{
handleMove
}
>
<
View
style=
{
{
width
:
data
.
thumbInnerRadius
*
2
,
height
:
data
.
thumbInnerRadius
*
2
,
borderRadius
:
data
.
thumbInnerRadius
,
backgroundColor
:
nowColor
,
}
}
/>
<
View
className=
{
styles
.
panel
}
>
<
View
className=
{
styles
.
configList
}
>
<
Image
src=
{
imgs
.
icon_bhd
}
className=
{
styles
.
icoImg
}
/>
<
View
className=
{
styles
.
slider
}
>
<
Slider
activeColor=
"#fff"
backgroundColor=
"#333333"
min=
{
0
}
max=
{
1000
}
step=
{
1
}
value=
{
dataState
.
temp_value
}
onChange=
{
e
=>
handleStateChange
(
'temp_value'
,
e
)
}
/>
</
View
>
<
Text
className=
{
styles
.
SliderValue
}
>
{
toParseInt
((
dataState
.
temp_value
/
1000
)
*
100
)
}
%
</
Text
>
</
View
>
<
View
className=
{
styles
.
configList
}
>
<
Image
src=
{
imgs
.
icon_ld
}
className=
{
styles
.
icoImg
}
/>
<
View
className=
{
styles
.
slider
}
>
<
Slider
activeColor=
"#fff"
backgroundColor=
"#333333"
min=
{
10
}
max=
{
1000
}
step=
{
1
}
value=
{
dataState
.
bright_value
}
onChange=
{
e
=>
handleStateChange
(
'bright_value'
,
e
)
}
/>
</
View
>
<
Text
className=
{
styles
.
SliderValue
}
>
{
toParseInt
((
dataState
.
bright_value
/
990
)
*
100
)
}
%
</
Text
>
</
View
>
<
View
className=
{
styles
.
configList
}
>
{
colorArr
.
map
(
item
=>
(
<
View
className=
{
styles
.
colorCircle
}
style=
{
{
backgroundColor
:
item
.
color
,
borderColor
:
item
.
active
?
'red'
:
'white'
}
}
key=
{
item
.
color
}
onClick=
{
e
=>
handleCirleClick
(
e
,
item
)
}
>
{
item
.
active
&&
<
View
className=
{
styles
.
cutBar
}
>
-
</
View
>
}
</
View
>
))
}
{
addFlag
&&
(
<
View
className=
{
`${styles.colorCircle} ${styles.addBar}`
}
onClick=
{
handleCircleAdd
}
>
<
View
className=
{
styles
.
addStyle
}
>
+
</
View
>
</
View
>
)
}
</
View
>
</
View
>
</
View
>
);
};
export
default
HubColorCircle
;
// nativeEvent
// changedTouches - 在上一次事件之后,所有发生变化的触摸事件的数组集合(即上一次事件后,所有移动过的触摸点)
// identifier - 触摸点的 ID
// locationX - 触摸点相对于父元素的横坐标
// locationY - 触摸点相对于父元素的纵坐标
// pageX - 触摸点相对于根元素的横坐标
// pageY - 触摸点相对于根元素的纵坐标
// target - 触摸点所在的元素 ID
// timestamp - 触摸事件的时间戳,可用于移动速度的计算
// touches - 当前屏幕上的所有触摸点的集合
// 一个gestureState对象有如下的字段:
// stateID - 触摸状态的 ID。在屏幕上有至少一个触摸点的情况下,这个 ID 会一直有效。
// moveX - 最近一次移动时的屏幕横坐标
// moveY - 最近一次移动时的屏幕纵坐标
// x0 - 当响应器产生时的屏幕坐标
// y0 - 当响应器产生时的屏幕坐标
// dx - 从触摸操作开始时的累计横向路程
// dy - 从触摸操作开始时的累计纵向路程
// vx - 当前的横向移动速度
// vy - 当前的纵向移动速度
// numberActiveTouches - 当前在屏幕上的有效触摸点的数量
export
default
HubCircle
;
src/pages/home/index.module.less
View file @
5233fb98
@subtractHeight:
200r
px;
@subtractHeight:
100
px;
.home {
height: 100vh;
...
...
@@ -38,17 +38,17 @@
}
.switch {
width:
120r
px;
height:
120r
px;
width:
60
px;
height:
60
px;
background: #43aaff;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
position: absolute;
border: 4
r
px solid rgba(0, 0, 0, 0.8);
border: 4px solid rgba(0, 0, 0, 0.8);
z-index: 500;
left: calc(50% -
60r
px);
left: calc(50% -
40
px);
bottom: 100rpx;
}
...
...
@@ -57,6 +57,6 @@
}
.CombinedShape {
width:
60r
px;
height:
60r
px;
width:
40
px;
height:
40
px;
}
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