2024-09-09 13:12:59 +08:00
|
|
|
import React, { useState, useEffect, useRef } from "react";
|
|
|
|
export default function MySlider({
|
|
|
|
lower_bound,
|
|
|
|
upper_bound,
|
|
|
|
step,
|
|
|
|
unit,
|
|
|
|
unitSite = "right",
|
|
|
|
width = 0,
|
|
|
|
onChange,
|
|
|
|
handleFunc = () => {},
|
|
|
|
disabled = false,
|
|
|
|
thumbSize = 25,
|
|
|
|
stepValues = [],
|
|
|
|
hasInfinity,
|
|
|
|
leftValue = lower_bound,
|
|
|
|
rightValue = stepValues[stepValues.length - 1],
|
|
|
|
maximumTrackTintColor = "#dcdbdb",
|
|
|
|
minimumTrackTintColor = "#577BFF",
|
|
|
|
processHeight = 7,
|
|
|
|
}) {
|
|
|
|
// const leftProcess = useRef(0);
|
|
|
|
// const rightProcess = useRef(0);
|
|
|
|
|
|
|
|
const [leftProcess, setLeftProcess] = useState(0);
|
|
|
|
const [rightProcess, setRightProcess] = useState(0);
|
|
|
|
const [stepNum, setStepNum] = useState(stepValues.length - 1);
|
|
|
|
const [processWidth, setProcessWidth] = useState(330);
|
|
|
|
const currentLeftValue = useRef(leftValue);
|
|
|
|
const currentRightValue = useRef(rightValue);
|
|
|
|
useEffect(() => {
|
|
|
|
setProcessWidth(width - thumbSize * 2);
|
|
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
|
|
const currentLeftProcess =
|
|
|
|
(stepValues.indexOf(leftValue) * step - lower_bound) /
|
|
|
|
(upper_bound - lower_bound);
|
|
|
|
const currentRightProcess =
|
|
|
|
(stepValues.indexOf(rightValue) * step - lower_bound) /
|
|
|
|
(upper_bound - lower_bound);
|
|
|
|
setLeftProcess(currentLeftProcess);
|
|
|
|
setRightProcess(currentRightProcess);
|
|
|
|
currentLeftValue.current = leftValue;
|
|
|
|
currentRightValue.current = rightValue;
|
|
|
|
}, [leftValue, rightValue]);
|
|
|
|
// 左侧滑块事件
|
|
|
|
const _onPanResponderGrantLeft = () => {
|
|
|
|
handleFunc && handleFunc();
|
|
|
|
};
|
|
|
|
|
|
|
|
const _onPanResponderEndLeft = () => {
|
|
|
|
handleFunc && handleFunc();
|
|
|
|
};
|
|
|
|
const _onPanResponderMoveLeft = (e) => {
|
|
|
|
if (e.touches.length == 1) {
|
|
|
|
const process = (e.touches[0].pageX - thumbSize * 2) / processWidth;
|
|
|
|
_changeProcess(process, "left");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// 右侧滑块事件
|
|
|
|
const _onPanResponderGrantRight = (e, gestureState) => {
|
|
|
|
handleFunc && handleFunc();
|
|
|
|
};
|
|
|
|
const _onPanResponderEndRight = (e, gestureState) => {
|
|
|
|
handleFunc && handleFunc();
|
|
|
|
};
|
|
|
|
|
|
|
|
const _onPanResponderMoveRight = (e) => {
|
|
|
|
if (e.touches.length == 1) {
|
|
|
|
const process = (e.touches[0].pageX - thumbSize / 2 - 40) / processWidth;
|
|
|
|
_changeProcess(process, "right");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const _changeProcess = (changeProcess, direction) => {
|
|
|
|
// 判断滑动开关
|
|
|
|
if (disabled) return;
|
|
|
|
// 按步长比例变化刻度
|
|
|
|
changeProcess =
|
|
|
|
changeProcess > 1 ? 1 : changeProcess < 0 ? 0 : changeProcess;
|
|
|
|
const v = changeProcess * (upper_bound - lower_bound);
|
|
|
|
const newValue = Math.round(v / step) * step;
|
|
|
|
const newProcess = Math.round(newValue) / (upper_bound - lower_bound);
|
|
|
|
setStepNum(stepNum + 1);
|
|
|
|
if (process !== newProcess) {
|
|
|
|
if (direction == "left") {
|
|
|
|
const currentRightProcess =
|
|
|
|
(stepValues.indexOf(currentRightValue.current) * step - lower_bound) /
|
|
|
|
(upper_bound - lower_bound);
|
|
|
|
if (newProcess < currentRightProcess) {
|
|
|
|
const newLower =
|
|
|
|
stepValues[
|
|
|
|
Math.round(
|
|
|
|
(newProcess * (upper_bound - lower_bound) + lower_bound) / step
|
|
|
|
)
|
|
|
|
];
|
|
|
|
if (newLower <= currentRightValue.current - 3) {
|
|
|
|
setLeftProcess(newProcess);
|
|
|
|
setStepNum((old) => old + 1);
|
|
|
|
onChange({
|
|
|
|
lower_bound: newLower,
|
|
|
|
upper_bound: currentRightValue.current,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const currentLeftProcess =
|
|
|
|
(stepValues.indexOf(currentLeftValue.current) * step - lower_bound) /
|
|
|
|
(upper_bound - lower_bound);
|
|
|
|
|
|
|
|
if (newProcess > currentLeftProcess) {
|
|
|
|
const newUpper =
|
|
|
|
stepValues[
|
|
|
|
Math.round(
|
|
|
|
(newProcess * (upper_bound - lower_bound) + lower_bound) / step
|
|
|
|
)
|
|
|
|
];
|
|
|
|
if (newUpper >= currentLeftValue.current + 3) {
|
|
|
|
setRightProcess(newProcess);
|
|
|
|
setStepNum((old) => old - 1);
|
|
|
|
onChange({
|
|
|
|
lower_bound: currentLeftValue.current,
|
|
|
|
upper_bound: newUpper,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// setStepNum(stepNum - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
className="flex relative "
|
|
|
|
style={{
|
|
|
|
// height: "upper_bound-content",
|
|
|
|
width,
|
|
|
|
// flex: 1,
|
|
|
|
flexDirection: "row",
|
|
|
|
justifyContent: "center",
|
|
|
|
alignItems: "center",
|
|
|
|
marginBottom: 36,
|
|
|
|
marginTop: 24,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<div style={{ width: "100%", position: "relative" }}>
|
|
|
|
{/* 格子步数 */}
|
|
|
|
{hasInfinity && (
|
|
|
|
<div
|
|
|
|
className="flex flex-row justify-between items-center absolute"
|
|
|
|
style={{
|
|
|
|
top: -23,
|
|
|
|
flex: 1,
|
|
|
|
width: "100%",
|
|
|
|
// height: 40,
|
|
|
|
padding: 17,
|
|
|
|
paddingRight: 20,
|
|
|
|
marginLeft: -12,
|
|
|
|
// backgroundColor: "#fff",
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{stepValues.map((item, index) => (
|
|
|
|
<div
|
|
|
|
key={index}
|
|
|
|
style={{
|
|
|
|
backgroundColor:
|
|
|
|
item >= leftValue && item <= rightValue
|
|
|
|
? minimumTrackTintColor
|
|
|
|
: maximumTrackTintColor,
|
|
|
|
width: thumbSize / 2,
|
|
|
|
height: thumbSize / 2,
|
|
|
|
borderRadius: 50,
|
|
|
|
}}
|
|
|
|
></div>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
backgroundColor: maximumTrackTintColor,
|
|
|
|
height: processHeight,
|
|
|
|
width: processWidth,
|
|
|
|
position: "absolute",
|
|
|
|
marginTop: -processHeight / 2,
|
|
|
|
left: thumbSize / 2,
|
|
|
|
zIndex: 1,
|
|
|
|
borderRadius: 50,
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
backgroundColor: minimumTrackTintColor,
|
|
|
|
width: (rightProcess - leftProcess) * processWidth,
|
|
|
|
height: processHeight,
|
|
|
|
marginLeft: thumbSize / 2 + leftProcess * processWidth,
|
|
|
|
position: "absolute",
|
|
|
|
marginTop: -processHeight / 2,
|
|
|
|
left: 0,
|
|
|
|
zIndex: 10,
|
|
|
|
borderRadius: 50,
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
{/* 左侧控件 */}
|
|
|
|
<div
|
|
|
|
transition={1000}
|
|
|
|
// style={tailwind("w-full h-full rounded-lg overflow-hidden")}
|
|
|
|
style={{
|
|
|
|
position: "absolute",
|
|
|
|
left: leftProcess * processWidth,
|
|
|
|
zIndex: 10,
|
|
|
|
width: thumbSize,
|
|
|
|
height: thumbSize,
|
|
|
|
borderRadius: 50,
|
|
|
|
backgroundColor: "#ff75c8",
|
|
|
|
borderColor: "#ffffff",
|
|
|
|
borderWidth: 2,
|
|
|
|
}}
|
|
|
|
draggable={true}
|
|
|
|
onTouchStart={_onPanResponderGrantLeft}
|
|
|
|
onTouchMove={_onPanResponderMoveLeft}
|
|
|
|
onTouchEnd={_onPanResponderEndLeft}
|
|
|
|
></div>
|
|
|
|
{/* 右侧控件 */}
|
|
|
|
<div
|
|
|
|
transition={1000}
|
|
|
|
// style={tailwind("w-full h-full rounded-lg overflow-hidden")}
|
|
|
|
style={{
|
|
|
|
position: "absolute",
|
|
|
|
left: rightProcess * processWidth,
|
|
|
|
zIndex: 10,
|
|
|
|
width: thumbSize,
|
|
|
|
height: thumbSize,
|
|
|
|
backgroundColor: "#fff",
|
|
|
|
borderRadius: 50,
|
|
|
|
backgroundColor: "#ff75c8",
|
|
|
|
borderColor: "#ffffff",
|
|
|
|
borderWidth: 2,
|
|
|
|
}}
|
|
|
|
draggable={true}
|
|
|
|
onTouchStart={_onPanResponderGrantRight}
|
|
|
|
onTouchMove={_onPanResponderMoveRight}
|
|
|
|
onTouchEnd={_onPanResponderEndRight}
|
|
|
|
></div>
|
|
|
|
|
|
|
|
<div
|
|
|
|
className="flex flex-row justify-between items-center absolute text-lg"
|
|
|
|
style={{
|
|
|
|
top: -48,
|
|
|
|
right: 24,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{unitSite == "left" && (
|
|
|
|
<span
|
|
|
|
style={{
|
|
|
|
maxWidth: thumbSize * 2,
|
|
|
|
color: "#ff75c8",
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{unit}
|
|
|
|
</span>
|
|
|
|
)}
|
|
|
|
<span
|
|
|
|
style={{
|
|
|
|
color: "#ff75c8",
|
|
|
|
}}
|
|
|
|
>
|
2024-09-09 15:56:03 +08:00
|
|
|
{hasInfinity && leftProcess == 1 ? "∞" : leftValue}
|
2024-09-09 13:12:59 +08:00
|
|
|
</span>
|
|
|
|
<span
|
|
|
|
style={{
|
|
|
|
marginHorizontal: 4,
|
|
|
|
color: "#ff75c8",
|
|
|
|
}}
|
|
|
|
>
|
2024-09-11 14:22:02 +08:00
|
|
|
~
|
2024-09-09 13:12:59 +08:00
|
|
|
</span>
|
|
|
|
<span
|
2024-09-11 14:22:02 +08:00
|
|
|
className={hasInfinity ? "text-xl" : ""}
|
2024-09-09 13:12:59 +08:00
|
|
|
style={{
|
|
|
|
color: "#ff75c8",
|
|
|
|
}}
|
|
|
|
>
|
2024-09-09 15:56:03 +08:00
|
|
|
{hasInfinity && rightProcess >= 1 ? "∞" : rightValue}
|
2024-09-09 13:12:59 +08:00
|
|
|
</span>
|
|
|
|
{unitSite == "right" && (
|
|
|
|
<span
|
|
|
|
style={{
|
|
|
|
maxWidth: thumbSize * 2,
|
|
|
|
color: "#ff75c8",
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{unit}
|
|
|
|
</span>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
className="absolute text-white text-sm flex flex-row justify-between"
|
|
|
|
style={{
|
|
|
|
width: width - 22,
|
|
|
|
left: 0,
|
|
|
|
top: 20,
|
|
|
|
color: "#ffffff80",
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<span
|
|
|
|
className="text-sm"
|
|
|
|
style={{
|
|
|
|
minWidth: thumbSize,
|
|
|
|
maxWidth: thumbSize * 2,
|
|
|
|
color: "#ffffff80",
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{lower_bound}
|
|
|
|
</span>
|
|
|
|
<span
|
|
|
|
style={{
|
|
|
|
minWidth: thumbSize,
|
|
|
|
color: "#ffffff80",
|
|
|
|
}}
|
|
|
|
>
|
2024-09-09 15:56:03 +08:00
|
|
|
{hasInfinity ? "∞" : upper_bound}
|
2024-09-09 13:12:59 +08:00
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|