Skip to content

Commit

Permalink
feat: ✨add mid line resizable
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyjone committed Apr 20, 2023
1 parent d00b070 commit 4cd6dec
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 92 deletions.
4 changes: 2 additions & 2 deletions demo/demo.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div style="top: 20vh; width: 100%; height: 500px">
<x-gantt :data="ganttData">
<x-gantt :data="ganttData" style="padding-left: 20vh">
<x-gantt-column label="group1">
<x-gantt-column prop="id" width="200px"></x-gantt-column>
<x-gantt-column label="group2">
Expand Down Expand Up @@ -40,7 +40,7 @@ let id = 0;
const ganttData = reactive<any>([]);
for (let i = 0; i < 500; i++) {
for (let i = 0; i < 50; i++) {
onAdd();
}
Expand Down
9 changes: 2 additions & 7 deletions src/components/column/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import Variables from '@/constants/vars';
import columnProps from './props';
import { defineComponent, useSlots, computed } from 'vue';
import { getColumnWidth } from './util';
import useStyle from '@/composables/useStyle';
import useSlotsBox from '@/composables/useSlotsBox';
Expand All @@ -41,17 +40,13 @@ const { $styleBox, rowHeight } = useStyle();
const { $slotsBox, isMerge } = useSlotsBox();
const realWidth = computed(() => {
let curWidth = getColumnWidth(
props?.width ?? Variables.default.tableColumnWidth
);
let curWidth = $slotsBox.tableHeaders.leafs[props!.__index ?? 1].width;
for (let i = (props.__index ?? 1) + 1; i < $slotsBox.cols.length; i++) {
const col = $slotsBox.cols[i];
if (isMerge(col.props?.merge, props.data!)) {
curWidth += getColumnWidth(
col.props?.width ?? Variables.default.tableColumnWidth
);
curWidth += $slotsBox.tableHeaders.leafs[i].width;
} else {
break;
}
Expand Down
3 changes: 0 additions & 3 deletions src/components/column/util.ts

This file was deleted.

40 changes: 29 additions & 11 deletions src/components/common/TableHeader.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
<template>
<table class="xg-table-header" cellpadding="0" cellspacing="0" border="0">
<colgroup>
<template v-for="(c, i) in $slotsBox.cols" :key="i">
<col
:width="
getColumnWidth(
c.props?.width ?? Variables.default.tableColumnWidth
) + 'px'
"
/>
<template v-for="(c, i) in $slotsBox.tableHeaders.leafs" :key="i">
<col :width="`${c.width}px`" />
</template>
</colgroup>
<thead>
<tr v-for="(r, trIndex) in $slotsBox.tableHeaders.headers" :key="trIndex">
<th
v-for="(c, i) in r"
ref="headerRef"
:key="i"
class="xg-table-header-cell"
:class="['xg-table-header-cell', 'cell-resizable']"
:style="{ ...$styleBox.getBorderColor() }"
:colspan="c.colSpan"
:rowspan="c.rowSpan"
Expand All @@ -31,11 +26,19 @@
<script lang="ts" setup>
import useSlotsBox from '@/composables/useSlotsBox';
import useStyle from '@/composables/useStyle';
import Variables from '@/constants/vars';
import { getColumnWidth } from '../column/util';
import { onMounted, ref } from 'vue';
const { $slotsBox } = useSlotsBox();
const { $styleBox } = useStyle();
const headerRef = ref<HTMLElement[]>([]);
onMounted(() => {
headerRef.value.forEach(item => {
item.addEventListener('pointerdown', e => {
console.log(e);
});
});
});
</script>

<style lang="scss" scoped>
Expand All @@ -61,5 +64,20 @@ const { $styleBox } = useStyle();
border-right: 1px solid;
padding: 0 20px;
}
.xg-table-header-cell.cell-resizable {
pointer-events: none;
&::after {
content: '';
position: absolute;
right: -5px;
top: 0;
bottom: 0;
width: 10px;
cursor: col-resize;
pointer-events: auto;
}
}
}
</style>
109 changes: 96 additions & 13 deletions src/components/root/index.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<template>
<div
ref="rootRef"
class="xg-root"
:style="{ ...$styleBox.getBorder(), ...$styleBox.getBorderColor() }"
>
<!-- 左侧表格 -->
<sync-scroll-container
ref="tableRef"
vertical
class="table-container"
class="xg-table-container"
:style="{ width: tableWidth + 'px' }"
hide-scroll
disable-horizontal
Expand All @@ -20,14 +21,25 @@
<TableBody :gap="scrollGapSize" />
</sync-scroll-container>

<div class="mid-separate-line" />
<!-- 中分线 -->
<div
ref="midLineRef"
class="xg-mid-separate-line"
@pointerdown="onDownMidLine"
/>
<!-- 移动示意线 -->
<div
v-show="showLine"
class="xg-move-line"
:style="{ left: lineLeft + 'px' }"
/>

<!-- 右侧甘特 -->
<sync-scroll-container
ref="ganttRef"
vertical
horizontal
class="gantt-container"
class="xg-gantt-container"
:group="containerId"
:style="{ width: `calc(100% - ${tableWidth}px - 3px)` }"
>
Expand All @@ -49,20 +61,33 @@ import GanttBody from '@/components/common/GanttBody.vue';
import useSlotsBox from '@/composables/useSlotsBox';
import useTableWidth from '@/composables/useTableWidth';
import { uuid } from '@/utils/common';
import { getCurrentInstance, onMounted, onUpdated, ref, toRefs } from 'vue';
import {
DefineComponent,
getCurrentInstance,
onMounted,
onUpdated,
ref,
toRefs
} from 'vue';
import rootProps from './rootProps';
import useData from '@/composables/useData';
import useStyle from '@/composables/useStyle';
import { useResizeObserver } from '@vueuse/core';
import useParam from '@/composables/useParam';
import useGanttHeader from '@/composables/useGanttHeader';
import useDrag from '@/composables/useDrag';
import useElement from '@/composables/useElement';
const containerId = uuid(10);
const props = defineProps(rootProps);
// #region 挂载实例
const { rootRef } = useElement();
// #endregion
// #region 获取表格下方的滚动条 gap
const tableRef = ref<any>(null);
const ganttRef = ref<any>(null);
const tableRef = ref<DefineComponent | null>(null);
const ganttRef = ref<DefineComponent | null>(null);
const scrollGapSize = ref(0);
function getScrollGapSize() {
Expand All @@ -83,8 +108,8 @@ onUpdated(getScrollGapSize);
const { $param } = useParam();
onMounted(() => {
$param.rootHeight = Math.max(
ganttRef.value.$el.offsetHeight,
ganttRef.value.$el.clientHeight
ganttRef.value!.$el.offsetHeight,
ganttRef.value!.$el.clientHeight
);
});
// #endregion
Expand All @@ -95,7 +120,7 @@ setStyles(props);
// #endregion
// #region 处理插槽内容
const { setSlots } = useSlotsBox();
const { setSlots, $slotsBox } = useSlotsBox();
setSlots(props.slots);
// #endregion
Expand All @@ -116,31 +141,89 @@ const { setGanttHeaders } = useGanttHeader();
onMounted(() => useResizeObserver(ganttRef.value?.$el, setGanttHeaders));
// #endregion
// #region 加载示意线
const { showLine, onDrag, lineLeft } = useDrag();
function onDownMidLine(e: PointerEvent) {
const rootRect = rootRef.value?.getBoundingClientRect();
lineLeft.value = e.clientX - (rootRect?.left ?? 0);
$param.showMoveLine = true;
}
const midLineRef = ref<HTMLElement | null>(null);
onMounted(() => {
onDrag(midLineRef, {
reset: true,
onMove: (x, e) => {
const tableRect = tableRef.value?.$el.getBoundingClientRect();
const ganttRect = ganttRef.value?.$el.getBoundingClientRect();
if (e.clientX < tableRect.left) {
return;
}
if (e.clientX > ganttRect.right - 100) {
return;
}
lineLeft.value = e.clientX;
},
onEnd: x => {
$param.showMoveLine = false;
$slotsBox.tableHeaders.leafs[
$slotsBox.tableHeaders.leafs.length - 1
].width += x;
}
});
});
// #endregion
console.log('.....root', getCurrentInstance());
</script>

<style scoped lang="scss">
.xg-root {
box-sizing: border-box;
overflow: hidden;
position: relative;
width: 100%;
height: 100%;
}
.table-container {
.xg-table-container {
height: 100%;
display: inline-block;
position: relative;
}
.mid-separate-line {
.xg-mid-separate-line {
width: 3px;
height: 100%;
display: inline-block;
background-color: black;
position: relative;
background-color: #e5e5e5;
transition: background-color 0.1s;
&:hover {
background-color: #d5d5d5;
box-shadow: 0 0 10px #d5d5d5;
cursor: col-resize;
}
}
.xg-move-line {
position: absolute;
top: 0;
height: 100%;
width: 0px;
z-index: 100;
border-left: 1px dashed #d5d5d5;
}
.gantt-container {
.xg-gantt-container {
height: 100%;
display: inline-block;
}
Expand Down
Loading

0 comments on commit 4cd6dec

Please sign in to comment.