import { Popover } from "../../Popover"; import createField from "../../utils/createField"; import { useClassList } from "../../utils/useProps" import { Draggable } from "../../Draggable"; import { createEffect, For, onMount, Show } from "solid-js"; type SliderProps = { classList?: any, class?: string, style?: any, range?: boolean, min?: number, max?: number, step?: number, value?: number | number[] | Function[], disabled?: boolean, tipFormatter?: Function, marks?: any, onChange?: Function } export function Slider (props: SliderProps) { let rail: any; let leftDrag: any; let rightDrag: any; let pop: any; let popRight: any; let min = props.min ?? 0; let max = props.max ?? 100; const step = props.step ?? 1.00; const range = props.range ?? false; const [value, setValue] = createField(props, range ? [0, 0] : 0); const classList = () => useClassList(props, 'cm-slider', { 'cm-slider-disabled': props.disabled }); let snap = () => { const rect = rail.getBoundingClientRect(); const allW = rect.width; return allW / (max - min) * step; }; // 根据值计算位置 const calculateLeftRight = () => { const val = range ? value() : [min, value()]; const trackWidth = Math.abs(val[1] - val[0]) / (max - min) * 100; const trackLeft = (val[0] - min) / (max - min) * 100; const handleRight = (val[1] - min) / (max - min) * 100; return {left: trackLeft, width: trackWidth, right: handleRight}; } const trackStyle = () => { const ret = calculateLeftRight(); return {left: ret.left + '%', width: ret.width + '%'}; }; const contextLeft = () => { const v = range ? value()[0] : value(); if (props.tipFormatter) { return props.tipFormatter(v); } return v; } const contextRight = () => { if (props.tipFormatter) { return props.tipFormatter(value()[1]); } return value()[1]; } // 值改变后同步拖拽点的位置 createEffect(() => { const ret = calculateLeftRight(); const rect = rail.getBoundingClientRect(); const leftX = range ? rect.width * ret.left / 100 : rect.width * ret.right / 100; const rightX = range ? rect.width * (ret.left + ret.width) / 100 : 0; if (leftDrag) { leftDrag.setPosition({ x: leftX, y: 0 }); } if (rightDrag) { rightDrag.setPosition({ x: rightX, y: 0 }); } }); const toFixed = (num: number) => { let r; try { r = step.toString().split('.')[1].length; } catch (e) { r = 0; } const m = Math.pow(10, r); return Math.round(num * m) / m; } //左侧拖拽 const onLeftDrag = (e: any, data: any) => { const railRect = rail.getBoundingClientRect(); const allW = railRect.width; const v = toFixed(data.x / allW * (max - min) + min); setTimeout(() => { pop && pop.updatePosition(); }) if (range && v > value()[1]) { return false; } let val = range ? [v, Math.max(v, value()[1])] : v; setValue(val); props.onChange && props.onChange(val); } //右侧拖拽 const onRightDrag = (e: any, data: any) => { const railRect = rail.getBoundingClientRect(); const allW = railRect.width; const v = toFixed(data.x / allW * (max - min) + min); setTimeout(() => { popRight && popRight.updatePosition(); }); if (range && v < value()[0]) { return false; } let val = range ? [Math.min(value()[0], v), v] : v; setValue(val); props.onChange && props.onChange(val); } // 点击后改变值 const onMouseDown = (e: any) => { if (props.disabled) { return; } if (e.target.classList.contains('cm-slider-handle')) { return; } const slider = e.target.closest('.cm-slider'); if (!slider) { return; } const sliderRect = slider.getBoundingClientRect(); const x = e.pageX - sliderRect.left; const railRect = rail.getBoundingClientRect(); const allW = railRect.width; const v = toFixed(Math.round(x / allW * (max - min) / step + min) * step); let val = value(); if (range) { const nearLeft = Math.abs(val[1] - v) > Math.abs(val[0] - v); val = nearLeft ? [v, val[1]] : [val[0], v]; setValue(val); props.onChange && props.onChange(val); } else { setValue(v); props.onChange && props.onChange(v); } } const steps = () => { if (!props.marks) { return []; } let arr = []; for (let i = min; i <= max; i += step) { if (props.marks[i]) { arr.push(i); } } return arr; } const marks = () => { if (props.marks) { const arr = []; for (let step in props.marks) { arr.push({ step: parseFloat(step), label: props.marks[step] }); } return arr; } return []; } return