主题色改为完整色板:画布 342x200,加明度条,删除右侧预设圆点
用户:「还是不对呀,需要一个完整的色板,右侧那些默认颜色就不要了。」 两个改动: 1. 删掉右侧那排 12 个预设圆点($presets 变量、CSS、JS 同步逻辑一并删)。 色板本身能取任意颜色,再摆一排样例是重复,还挤占横向空间。 2. 色板做成「完整」的: 面板 248×246 → 372×357 画布 226×150 → 342×200(太小拖着不好定位颜色) 新增明度条,底色随当前色相实时刷新 —— 否则永远是灰阶,用户看不出拖到那里会得到什么颜色 面板加标题「选择颜色」,按钮文案「确定」→「完成」 顺带简化光标定位: 原来 cursor 挂在 .cp 里,要靠两个 getBoundingClientRect 相减算偏移; 现在改挂到 .cp-sv-wrap(与 canvas 同级),坐标直接相对 canvas 算, 少一层偏移、少一个坑。 验证(浏览器实测): .color-preset 残留 0 个、.color-presets 容器 0 个 面板 372×357、画布 342×200,完整在视口内 色相 200° → 明度条背景 linear-gradient(#000, rgb(0,170,255)),确实跟着变 画布 80%/20% 处取色 → #2996cc,光标落在画布范围内 明度拖到 50% → #1a5e80(同色相压暗,符合预期) 手输 #2E7D5B → 隐藏字段 #2e7d5b,点完成关闭 4 个路由 200
This commit is contained in:
+39
-35
@@ -710,18 +710,18 @@
|
||||
}
|
||||
|
||||
/* ---------- 主题色选择器(后台软件编辑) ----------
|
||||
* 用户 2026-11-04:「还是不够丰富,让用户自己选:点击之后弹出一个颜色选择器。」
|
||||
* 用户 2026-11-04:「还是不对呀,需要一个完整的色板,右侧那些默认颜色就不要了。」
|
||||
*
|
||||
* 原来是原生 <input type="color">:只有个小方块,用户不知道能点,
|
||||
* 而且各浏览器系统面板样式不一。现在自带一个面板:
|
||||
* 色相/饱和度渐变板(Canvas)+ 明度滑块 + 十六进制输入。
|
||||
* 预设圆点保留为快捷色,但真正的能力是**任意取色**。
|
||||
* 现在的形态是一块**完整色板**(不是小浮窗):
|
||||
* 340×200 的色相/饱和度画布 + 色相条 + 明度条 + 十六进制输入。
|
||||
* 右侧那排预设圆点已删除 —— 既能任意取色,再摆一排样例就是重复。
|
||||
*
|
||||
* 交互约定:
|
||||
* - 点色块 → 面板出现(定位在其下方/上方,视空间而定)
|
||||
* - 在渐变板上拖动 → 实时更新;滑条调明度
|
||||
* - 十六进制框可手输,输入合法立即同步
|
||||
* - 点「确定」或点面板外 → 关闭,值已写入隐藏字段
|
||||
* - 点色块 → 色板出现(下方空间不够自动翻到上方)
|
||||
* - 画布内拖动 = 同时调饱和度与明度
|
||||
* - 色相条单独调 H;明度条单独调 V
|
||||
* - 十六进制框可手输,合法立即同步
|
||||
* - 点「完成」/ 点色板外 / Esc → 关闭(值早已写入隐藏字段)
|
||||
*/
|
||||
function bindColorPicker() {
|
||||
var rows = document.querySelectorAll('[data-colorpicker]');
|
||||
@@ -730,7 +730,6 @@
|
||||
(function (row) {
|
||||
var trigger = row.querySelector('[data-color-trigger]');
|
||||
var valueEl = row.querySelector('[data-color-value]');
|
||||
var presets = row.querySelectorAll('.color-preset');
|
||||
var reset = row.querySelector('.color-reset');
|
||||
var panel = row.querySelector('[data-color-panel]');
|
||||
if (!trigger || !valueEl || !panel) { return; }
|
||||
@@ -738,6 +737,7 @@
|
||||
var canvas = panel.querySelector('[data-cp-sv]');
|
||||
var cursor = panel.querySelector('[data-cp-cursor]');
|
||||
var hueEl = panel.querySelector('[data-cp-hue]');
|
||||
var valEl = panel.querySelector('[data-cp-val]'); // 明度条(可能不存在,做兼容)
|
||||
var prevEl = panel.querySelector('[data-cp-prev]');
|
||||
var hexEl = panel.querySelector('[data-cp-hex]');
|
||||
var okBtn = panel.querySelector('[data-cp-ok]');
|
||||
@@ -801,17 +801,16 @@
|
||||
}
|
||||
|
||||
function moveCursor() {
|
||||
/* ⚠️ 两个坑,都踩过:
|
||||
* ① cursor 是 position:absolute 相对 .cp 定位,canvas 在 .cp 的
|
||||
* 内边距里侧 —— 要补 offsetLeft/offsetTop,否则整体偏移;
|
||||
* ② canvas 的**显示尺寸**受 CSS width:100% 影响,不等于其内部
|
||||
* 像素宽高(220×150)。按内部尺寸算会越拉越偏。
|
||||
* 必须用 getBoundingClientRect() 的宽高。 */
|
||||
var rect = canvas.getBoundingClientRect();
|
||||
var w = rect.width || canvas.width;
|
||||
var h = rect.height || canvas.height;
|
||||
cursor.style.left = (canvas.offsetLeft + hsv.s * w) + 'px';
|
||||
cursor.style.top = (canvas.offsetTop + (1 - hsv.v) * h) + 'px';
|
||||
/* cursor 现在是 .cp-sv-wrap 的子元素(和 canvas 同级),
|
||||
* 所以坐标可以直接相对 canvas 自己算 —— 不用再管 .cp 的 padding:
|
||||
* left/top 相对 wrap,wrap 和 canvas 左/上边重合。
|
||||
* 但仍要注意:canvas 显示尺寸(CSS width:100%)≠ 内部像素宽高,
|
||||
* 必须用 getBoundingClientRect() 的宽高。 */
|
||||
var br = canvas.getBoundingClientRect();
|
||||
var w = br.width || canvas.width;
|
||||
var h = br.height || canvas.height;
|
||||
cursor.style.left = (hsv.s * w) + 'px';
|
||||
cursor.style.top = ((1 - hsv.v) * h) + 'px';
|
||||
cursor.style.background = curHex();
|
||||
}
|
||||
|
||||
@@ -824,16 +823,19 @@
|
||||
if (prevEl) { prevEl.style.background = hex; }
|
||||
if (!skipHex && hexEl) { hexEl.value = hex.toUpperCase(); }
|
||||
hueEl.value = Math.round(hsv.h);
|
||||
if (valEl) { valEl.value = Math.round(hsv.v * 100); }
|
||||
drawSV();
|
||||
drawValTrack();
|
||||
moveCursor();
|
||||
syncPresets(hex);
|
||||
}
|
||||
|
||||
function syncPresets(v) {
|
||||
for (var k = 0; k < presets.length; k++) {
|
||||
var same = (presets[k].getAttribute('data-color') || '').toLowerCase() === (v || '').toLowerCase();
|
||||
if (same) { presets[k].classList.add('on'); } else { presets[k].classList.remove('on'); }
|
||||
}
|
||||
/* 明度条的底色要跟着当前色相变 —— 否则永远是灰阶,
|
||||
* 用户看不清"拖到这里会得到什么颜色"。 */
|
||||
function drawValTrack() {
|
||||
if (!valEl) { return; }
|
||||
var pure = hsvToRgb(hsv.h, hsv.s, 1);
|
||||
var top = rgbToHex(pure[0], pure[1], pure[2]);
|
||||
valEl.style.background = 'linear-gradient(to right, #000, ' + top + ')';
|
||||
}
|
||||
|
||||
function setHex(hex, skipHex) {
|
||||
@@ -893,6 +895,14 @@
|
||||
syncAll();
|
||||
});
|
||||
|
||||
// ---- 明度滑条 ----
|
||||
if (valEl) {
|
||||
valEl.addEventListener('input', function () {
|
||||
hsv.v = (parseFloat(this.value) || 0) / 100;
|
||||
syncAll();
|
||||
});
|
||||
}
|
||||
|
||||
// ---- 十六进制手输 ----
|
||||
hexEl.addEventListener('input', function () {
|
||||
var v = this.value.trim();
|
||||
@@ -903,21 +913,15 @@
|
||||
|
||||
okBtn.addEventListener('click', function () { closePanel(); });
|
||||
|
||||
// ---- 预设 / 用默认 ----
|
||||
for (var j = 0; j < presets.length; j++) {
|
||||
presets[j].addEventListener('click', function () {
|
||||
setHex(this.getAttribute('data-color') || '');
|
||||
});
|
||||
}
|
||||
// ---- 用默认(清空 = 保存后回落到按 id 取的默认色)----
|
||||
if (reset) {
|
||||
reset.addEventListener('click', function () {
|
||||
// 清空 = 保存后回落到按 id 取的默认色
|
||||
valueEl.value = '';
|
||||
valueEl.setAttribute('name', 'color');
|
||||
syncPresets('');
|
||||
trigger.style.setProperty('--cur', '#cccccc');
|
||||
var hexTxt = trigger.querySelector('.color-trigger-hex');
|
||||
if (hexTxt) { hexTxt.textContent = '跟随默认'; }
|
||||
closePanel();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user