使用原生 js + div 实现,兼容多个平台
效果
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>手写调色板</title>
<style>
.picker {
position: relative;
margin: 25vh auto;
width: 50vh;
height: 50vh;
border-radius: 50%;
border: 1px solid #000;
box-sizing: border-box;
background-image: conic-gradient(
from -90deg,
#0ff 0%,
#00f 16.67%,
#f0f 33.34%,
#f00 50.01%,
#ff0 66.68%,
#0f0 83.35%,
#0ff 100%
);
}
.picker-handle {
position: absolute;
width: 5vh;
height: 5vh;
background-color: white;
border: 2px solid black;
border-radius: 50%;
cursor: move;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<div class="picker-container">
<div class="picker">
<div class="picker-handle"></div>
</div>
</div>
<script>
const picker = document.querySelector(".picker");
const handle = document.querySelector(".picker-handle");
const pickerRect = picker.getBoundingClientRect();
const pickerLeft = pickerRect.left;
const pickerTop = pickerRect.top;
const pickerRight = pickerRect.right;
const pickerBottom = pickerRect.bottom;
let isDragging = false;
// 鼠标按下事件处理程序
function onMouseDown(event) {
isDragging = true;
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
}
// 判断一个点是否在圆内
function isPointInCircle(x, y, center_x, center_y, radius) {
// 计算该点与圆心之间的距离
const distance = Math.sqrt(
Math.pow(x - center_x, 2) + Math.pow(y - center_y, 2)
);
// 如果该距离小于或等于圆的半径,则该点在圆内,返回该点坐标
if (distance <= radius) {
return {
x: x,
y: y,
};
} else {
// 否则计算给定点到圆心的连线与圆上的交点坐标
const angle = Math.atan2(y - center_y, x - center_x);
const point_x = center_x + radius * Math.cos(angle);
const point_y = center_y + radius * Math.sin(angle);
// 返回圆弧上的坐标
return {
x: point_x,
y: point_y,
};
}
}
// 鼠标移动事件处理程序
function onMouseMove(event) {
if (isDragging) {
const { left, height, width } = picker.getBoundingClientRect();
// 获取鼠标在 picker 内的位置
const centerX = pickerLeft + picker.offsetWidth / 2;
const centerY = pickerTop + picker.offsetHeight / 2;
const dx = event.clientX - centerX;
const dy = event.clientY - centerY;
// 计算角度并将其转换为色轮的颜色值
let angle = Math.atan2(dy, dx);
if (angle < 0) {
angle += 2 * Math.PI;
}
const hue = (angle * 180) / Math.PI;
// 计算小圆点相对于 picker 左上角的位置并限制范围
const handleLeft =
dx + picker.offsetWidth / 2 - handle.offsetWidth / 2;
const handleTop =
dy + picker.offsetHeight / 2 - handle.offsetHeight / 2;
// 计算鼠标距离中心的比例并应用到 HSL 颜色中
const distance = Math.sqrt(dx * dx + dy * dy);
const saturation = (distance / (picker.offsetWidth / 2)) * 100;
const lightness = 50;
// 获取颜色值并显示
const colorValue = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
document.body.style.backgroundColor = colorValue;
// console.log(121, { handleLeft, handleTop, width, height });
const { x, y } = isPointInCircle(
handleLeft,
handleTop,
width / 2,
height / 2,
width / 2
);
handle.style.left = `${x}px`;
handle.style.top = `${y}px`;
}
}
// 鼠标松开事件处理程序
function onMouseUp() {
isDragging = false;
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
}
// 添加事件监听器
handle.addEventListener("mousedown", onMouseDown);
</script>
</body>
</html>