Skip to content

Commit

Permalink
feat: ✨滑块的左右单独移动
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyjone committed May 12, 2023
1 parent dcedfe7 commit ddcc06d
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 39 deletions.
9 changes: 8 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ module.exports = {
'plugin:vue/vue3-recommended',
'plugin:prettier/recommended'
],
overrides: [],
overrides: [
{
files: ['*.vue'],
rules: {
'no-undef': 'off'
}
}
],
parserOptions: {
ecmaVersion: 'latest',
parser: '@typescript-eslint/parser',
Expand Down
7 changes: 6 additions & 1 deletion demo/demo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@
ellipsis
/>

<x-gantt-slider prop="name" :move="onMove"></x-gantt-slider>
<x-gantt-slider
prop="name"
:move="onMove"
resize-left
resize-right
></x-gantt-slider>
</x-gantt>
</div>

Expand Down
148 changes: 117 additions & 31 deletions src/components/slider/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
left: `${sliderLeft}px`,
width: `${sliderWidth}px`,
maxHeight: `${$styleBox.rowHeight}px`,
backgroundColor: props.bgColor,
backgroundColor: props?.bgColor,
height: height,
top:
height === '100%' ||
Expand All @@ -26,7 +26,17 @@
@pointerdown="onInAnchorDown"
></div>

<!-- 滑块主体 -->
<div class="xg-slider-content">
<!-- 左滑块 -->
<div
v-if="props.resizeLeft"
ref="resizeLeftRef"
class="xg-slider-resize left"
:style="{ backgroundColor: resizeColor }"
@pointerdown.stop="onResizeLeftDown"
/>

<slot v-if="slots.default" v-bind="props.data?.data" />

<div
Expand All @@ -40,6 +50,15 @@
: originData
}}
</div>

<!-- 右滑块 -->
<div
v-if="props.resizeRight"
ref="resizeRightRef"
class="xg-slider-resize right"
:style="{ backgroundColor: resizeColor }"
@pointerdown.stop="onResizeRightDown"
/>
</div>

<div
Expand All @@ -66,6 +85,7 @@ import useDrag from '@/composables/useDrag';
import useParam from '@/composables/useParam';
import useStyle from '@/composables/useStyle';
import { formatDate } from '@/utils/date';
import { blend } from '@/utils/colors';
import { isBoolean, isFunction } from 'lodash';
export default defineComponent({
Expand Down Expand Up @@ -95,6 +115,10 @@ const originData = computed(
() => props.label || (props.data?.data?.[props.prop ?? ''] ?? props.emptyData)
);
const resizeColor = computed(() =>
blend({ r: 93, g: 68, b: 15, a: 40 }, props?.bgColor || '#eca710')
);
// #region 计算滑块位置
const { toRowData } = useData();
const { ganttHeader } = useGanttHeader();
Expand All @@ -114,13 +138,17 @@ const sliderWidth = computed(
// #endregion
// #region 移动滑块
const canMove = computed(() => {
if (isBoolean(props.move)) return props.move;
if (isFunction(props.move)) {
return props.move(toRowData(props.data!));
const calcMove = (p: boolean | ((data: RowData) => boolean)) => {
if (isBoolean(p)) return p;
if (isFunction(p)) {
return p(toRowData(props.data!));
}
return false;
};
const canMove = computed(() => {
return calcMove(props.move);
});
const disableMove = ref(false);
function handleDisableMove() {
Expand All @@ -133,33 +161,33 @@ onMounted(() => {
});
});
const setStart = (() => {
const startDate = props.data?.start.clone();
return (x: number) => {
props.data?.setStart(
startDate!.getOffset(
(x / ganttColumnWidth.value) * currentMillisecond.value
),
ganttHeader.unit
);
};
})();
const setEnd = (() => {
const endDate = props.data?.end.clone();
return (x: number) =>
props.data?.setEnd(
endDate!.getOffset(
(x / ganttColumnWidth.value) * currentMillisecond.value
),
ganttHeader.unit
);
})();
let startDate = props.data?.start.clone();
const setStart = (x: number) => {
props.data?.setStart(
startDate!.getOffset(
(x / ganttColumnWidth.value) * currentMillisecond.value
),
ganttHeader.unit
);
};
let endDate = props.data?.end.clone();
const setEnd = (x: number) =>
props.data?.setEnd(
endDate!.getOffset((x / ganttColumnWidth.value) * currentMillisecond.value),
ganttHeader.unit
);
const sliderRef = ref(null) as Ref<HTMLElement | null>;
const { onDrag } = useDrag();
onDrag(sliderRef, {
disabled: () => !canMove.value || disableMove.value,
reset: true,
onStart: () => {
startDate = props.data?.start.clone();
endDate = props.data?.end.clone();
},
onMove: x => {
setStart(x);
Expand All @@ -168,6 +196,42 @@ onDrag(sliderRef, {
});
// #endregion
// #region 左滑块移动
function onResizeLeftDown() {
handleDisableMove();
}
const resizeLeftRef = ref(null) as Ref<HTMLElement | null>;
onDrag(resizeLeftRef, {
reset: true,
onStart: () => {
startDate = props.data?.start.clone();
},
onMove: x => {
setStart(x);
}
});
// #endregion
// #region 右滑块移动
function onResizeRightDown() {
handleDisableMove();
}
const resizeRightRef = ref(null) as Ref<HTMLElement | null>;
onDrag(resizeRightRef, {
reset: true,
onStart: () => {
endDate = props.data?.end.clone();
},
onMove: x => {
setEnd(x);
}
});
// #endregion
// #region inAnchor
function onInAnchorDown() {
handleDisableMove();
Expand All @@ -185,22 +249,44 @@ function onOutAnchorDown() {

<style lang="scss" scoped>
.xg-slider {
background-color: goldenrod;
position: absolute;
border-radius: 4px;
font-size: 10px;
padding: 0 12px;
transition: filter 0.2s;
.xg-slider-content {
background-color: goldenrod;
border-radius: 4px;
font-size: 10px;
height: 100%;
padding: 0 12px;
overflow: hidden;
position: relative;
.slider-text {
height: 100%;
display: flex;
align-items: center;
}
.xg-slider-resize {
width: 12px;
height: 100%;
position: absolute;
top: 0;
z-index: 1;
cursor: ew-resize;
&:hover {
filter: darkness(0.8);
}
}
.xg-slider-resize.left {
left: 0;
}
.xg-slider-resize.right {
right: 0;
}
}
&:hover {
Expand Down
15 changes: 9 additions & 6 deletions src/components/slider/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ export default {
* 背景颜色
*/
bgColor: {
type: String,
default: ''
type: String
},

/**
Expand Down Expand Up @@ -74,16 +73,20 @@ export default {
* 允许左侧移动
*/
resizeLeft: {
type: Boolean,
default: false
type: [Function, Boolean] as PropType<
boolean | ((data: RowData) => boolean)
>,
default: () => false
},

/**
* 允许右侧移动
*/
resizeRight: {
type: Boolean,
default: false
type: [Function, Boolean] as PropType<
boolean | ((data: RowData) => boolean)
>,
default: () => false
},

/**
Expand Down
3 changes: 3 additions & 0 deletions src/composables/useDrag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const lineLeft = ref(0);
const mousedown = ref(false);

interface DragOptions {
onStart?: (pos: { x: number; y: number }, e: MouseEvent) => void;
onMove?: (x: number, e: MouseEvent) => void;
onEnd?: (x: number, e: MouseEvent) => Promise<void> | void;
onFinally?: () => void;
Expand Down Expand Up @@ -37,6 +38,8 @@ export default () => {

const rect = (options?.target ?? el.value)?.getBoundingClientRect();
delta.value = Math.abs(left.value - (rect?.left ?? 0)) + e.offsetX;

options?.onStart?.(pos, e);
},

onMove: (pos, e) => {
Expand Down
32 changes: 32 additions & 0 deletions src/utils/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,35 @@ export function changeAlpha(color: string, alpha: number) {
a: Math.round(Math.min(1, Math.max(0, alpha)) * 100)
});
}

export function blend(fgColor: string | Rgba, bgColor: string | Rgba) {
if (typeof fgColor !== 'string' && (!fgColor || fgColor.r === undefined)) {
throw new TypeError(
'Expected a string or a {r, g, b[, a]} object as fgColor'
);
}

if (typeof bgColor !== 'string' && (!bgColor || bgColor.r === undefined)) {
throw new TypeError(
'Expected a string or a {r, g, b[, a]} object as bgColor'
);
}

const rgb1 = typeof fgColor === 'string' ? textToRgb(fgColor) : fgColor;
const r1 = rgb1.r / 255;
const g1 = rgb1.g / 255;
const b1 = rgb1.b / 255;
const a1 = rgb1.a !== undefined ? rgb1.a / 100 : 1;
const rgb2 = typeof bgColor === 'string' ? textToRgb(bgColor) : bgColor;
const r2 = rgb2.r / 255;
const g2 = rgb2.g / 255;
const b2 = rgb2.b / 255;
const a2 = rgb2.a !== undefined ? rgb2.a / 100 : 1;
const a = a1 + a2 * (1 - a1);
const r = Math.round(((r1 * a1 + r2 * a2 * (1 - a1)) / a) * 255);
const g = Math.round(((g1 * a1 + g2 * a2 * (1 - a1)) / a) * 255);
const b = Math.round(((b1 * a1 + b2 * a2 * (1 - a1)) / a) * 255);

const ret = { r, g, b, a: Math.round(a * 100) };
return rgbToHex(ret);
}

0 comments on commit ddcc06d

Please sign in to comment.