feat: 合并多选功能,解决冲突,升级版本到2.0.4

This commit is contained in:
奔跑的面条
2022-08-19 10:44:44 +08:00
55 changed files with 1746 additions and 641 deletions
@@ -11,17 +11,16 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { reactive, computed, watch } from 'vue'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import { useSettingStore } from '@/store/modules/settingStore/settingStore'
import { CreateComponentType } from '@/packages/index.d'
import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import throttle from 'lodash/throttle'
import cloneDeep from 'lodash/cloneDeep'
// 全局颜色
const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const chartEditStore = useChartEditStore()
const settingStore = useSettingStore()
@@ -49,6 +48,11 @@ const useComponentStyle = (attr?: Partial<{ x: number; y: number }>) => {
return componentStyle
}
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
// * 吸附距离
const minDistance = computed(() => {
return settingStore.getChartAlignRange
@@ -111,7 +115,7 @@ watch(
line.select.clear()
line.sorptioned.y = false
// 循环查询所有组件数据
const componentList = chartEditStore.getComponentList.map((e: CreateComponentType) => {
const componentList = chartEditStore.getComponentList.map((e: CreateComponentType | CreateComponentGroupType) => {
return {
id: e.id,
attr: e.attr
@@ -228,30 +232,6 @@ watch(
selectTarget.value.setPosition(componentRightX - selectW, selectTopY)
}
}
/*
* 我也不知道为什么这个不行,还没时间调
if(lineItem.includes('row')) {
selectY.forEach(sY => {
componentY.forEach(cY => {
if (isSorption(sY, cY)) {
line.select.set(lineItem, { y: cY })
}
})
})
return
}
if(lineItem.includes('col')) {
seletX.forEach(sX => {
componentX.forEach(cX => {
if (isSorption(sX, cX)) {
line.select.set(lineItem, { x: sX })
}
})
})
return
}
*/
})
})
}, 200),
@@ -267,7 +247,6 @@ watch(
if (!val) {
line.select.clear()
line.sorptioned.y = false
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, true)
}
}
)
@@ -0,0 +1,3 @@
import EditGroup from './index.vue'
export { EditGroup }
@@ -0,0 +1,122 @@
<template>
<div class="go-edit-group-box">
<edit-shape-box
:key="groupData.id"
:data-id="groupData.id"
:index="groupIndex"
:item="groupData"
:hiddenPoint="true"
:class="animationsClass(groupData.styles.animations)"
:style="{
...useComponentStyle(groupData.attr, groupIndex),
...useSizeStyle(groupData.attr),
...getFilterStyle(groupData.styles),
...getTransformStyle(groupData.styles)
}"
@click="mouseClickHandle($event, groupData)"
@mousedown="mousedownHandle($event, groupData)"
@mouseenter="mouseenterHandle($event, groupData)"
@mouseleave="mouseleaveHandle($event, groupData)"
@contextmenu="handleContextMenu($event, groupData, optionsHandle)"
>
<!-- 组合组件 -->
<edit-shape-box
v-for="item in groupData.groupList"
:key="item.id"
:data-id="item.id"
:index="groupIndex"
:item="item"
:hiddenPoint="true"
:style="{
...useComponentStyle(item.attr, groupIndex)
}"
>
<component
class="edit-content-chart"
:class="animationsClass(item.styles.animations)"
:is="item.chartConfig.chartKey"
:chartConfig="item"
:themeSetting="themeSetting"
:themeColor="themeColor"
:style="{
...useSizeStyle(item.attr),
...getFilterStyle(item.styles),
...getTransformStyle(item.styles)
}"
></component>
</edit-shape-box>
</edit-shape-box>
</div>
</template>
<script setup lang="ts">
import { computed, PropType } from 'vue'
import { MenuEnum } from '@/enums/editPageEnum'
import { chartColors } from '@/settings/chartThemes/index'
import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { MenuOptionsItemType } from '@/views/chart/hooks/useContextMenu.hook.d'
import { animationsClass, getFilterStyle, getTransformStyle } from '@/utils'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useContextMenu, divider } from '@/views/chart/hooks/useContextMenu.hook'
import { useMouseHandle } from '../../hooks/useDrag.hook'
import { useComponentStyle, useSizeStyle } from '../../hooks/useStyle.hook'
import { EditShapeBox } from '../../components/EditShapeBox'
const props = defineProps({
groupData: {
type: Object as PropType<CreateComponentGroupType>,
required: true
},
groupIndex: {
type: Number,
required: true
}
})
const chartEditStore = useChartEditStore()
const { handleContextMenu } = useContextMenu()
// 点击事件
const { mouseenterHandle, mouseleaveHandle, mousedownHandle, mouseClickHandle } = useMouseHandle()
// 右键
const optionsHandle = (
targetList: MenuOptionsItemType[],
allList: MenuOptionsItemType[],
targetInstance: CreateComponentType
) => {
// 多选
const moreMenuEnums = [MenuEnum.GROUP, MenuEnum.DELETE]
// 单选
const singleMenuEnums = [MenuEnum.UN_GROUP]
const filter = (menulist: MenuEnum[]) => {
const list: MenuOptionsItemType[] = []
allList.forEach(item => {
if (menulist.includes(item.key as MenuEnum)) {
list.push(item)
}
})
return list
}
// 多选处理
if (chartEditStore.getTargetChart.selectId.length > 1) {
return filter(moreMenuEnums)
} else {
return [...filter(singleMenuEnums), divider(), ...targetList]
}
}
// 配置项
const themeColor = computed(() => {
const chartThemeColor = chartEditStore.getEditCanvasConfig.chartThemeColor
return chartColors[chartThemeColor]
})
// 主题色
const themeSetting = computed(() => {
const chartThemeSetting = chartEditStore.getEditCanvasConfig.chartThemeSetting
return chartThemeSetting
})
</script>
@@ -1,21 +1,8 @@
<template>
<div class="go-flex-items-center">
<n-popover
class="edit-history-popover"
:show="showDropdownRef"
:show-arrow="false"
size="small"
trigger="click"
placement="top-start"
>
<n-popover class="edit-history-popover" :show-arrow="false" size="small" trigger="click" placement="top-start">
<template #trigger>
<n-button
class="go-mr-1"
secondary
size="small"
:disabled="options.length === 0"
@click="handleClick"
>
<n-button class="mr-10" secondary size="small" :disabled="options.length === 0">
<span class="btn-text">历史记录</span>
</n-button>
</template>
@@ -24,16 +11,11 @@
<n-scrollbar style="max-height: 500px">
<div
class="list-item go-flex-items-center go-ellipsis-1"
v-for="item in options"
:key="item.key"
v-for="(item, index) in options"
:key="index"
:title="item.label"
>
<n-icon
class="item-icon"
size="16"
:depth="2"
:component="item.icon"
/>
<n-icon class="item-icon" size="16" :depth="2" :component="item.icon" />
<n-text depth="2">{{ item.label }}</n-text>
</div>
</n-scrollbar>
@@ -55,7 +37,6 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import { icon } from '@/plugins'
import { renderIcon } from '@/utils'
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
import { historyActionTypeName } from '@/store/modules/chartHistoryStore/chartHistoryDefine'
import { CreateComponentType } from '@/packages/index.d'
@@ -64,20 +45,12 @@ import reverse from 'lodash/reverse'
import {
HistoryItemType,
HistoryTargetTypeEnum,
HistoryActionTypeEnum,
HistoryActionTypeEnum
} from '@/store/modules/chartHistoryStore/chartHistoryStore.d'
const {
DesktopOutlineIcon,
PencilIcon,
TrashIcon,
CopyIcon,
LayersIcon,
DuplicateIcon,
HelpOutlineIcon,
} = icon.ionicons5
const { StackedMoveIcon } = icon.carbon
const showDropdownRef = ref(false)
const { DesktopOutlineIcon, PencilIcon, TrashIcon, CopyIcon, LayersIcon, DuplicateIcon, HelpOutlineIcon } =
icon.ionicons5
const { StackedMoveIcon, Carbon3DCursorIcon, Carbon3DSoftwareIcon } = icon.carbon
const chartHistoryStoreStore = useChartHistoryStore()
@@ -106,6 +79,10 @@ const iconHandle = (e: HistoryItemType) => {
return StackedMoveIcon
case HistoryActionTypeEnum.ADD:
return DuplicateIcon
case HistoryActionTypeEnum.GROUP:
return Carbon3DCursorIcon
case HistoryActionTypeEnum.UN_GROUP:
return Carbon3DSoftwareIcon
default:
return PencilIcon
}
@@ -116,10 +93,11 @@ const labelHandle = (e: HistoryItemType) => {
// 画布编辑
if (e.targetType === HistoryTargetTypeEnum.CANVAS) {
return historyActionTypeName[HistoryTargetTypeEnum.CANVAS]
} else if (e.actionType === HistoryActionTypeEnum.GROUP || e.actionType === HistoryActionTypeEnum.UN_GROUP) {
return `${historyActionTypeName[e.actionType]}`
} else if (e.historyData.length) {
return `${historyActionTypeName[e.actionType]} - ${(e.historyData[0] as CreateComponentType).chartConfig.title}`
}
return `${historyActionTypeName[e.actionType]} - ${
(e.historyData as CreateComponentType).chartConfig.title
}`
}
const options = computed(() => {
@@ -127,16 +105,14 @@ const options = computed(() => {
const options = backStack.map((e: HistoryItemType) => {
return {
label: labelHandle(e),
key: e.id,
icon: iconHandle(e),
icon: iconHandle(e)
}
})
return reverse(options)
})
const handleClick = () => {
showDropdownRef.value = !showDropdownRef.value
}
return reverse(options.filter(item => {
return item.label
}))
})
</script>
<style lang="scss" scoped>
@@ -1,5 +1,5 @@
<template>
<div class="go-edit-range go-transition" :style="rangeStyle" @mousedown="mousedownHandleUnStop($event, undefined)">
<div class="go-edit-range go-transition" :style="rangeStyle" @mousedown="mousedownBoxSelect($event, undefined)">
<slot></slot>
<!-- 水印 -->
<edit-watermark></edit-watermark>
@@ -7,6 +7,8 @@
<edit-rule></edit-rule>
<!-- 拖拽时的辅助线 -->
<edit-align-line></edit-align-line>
<!-- 框选时的样式框 -->
<edit-select></edit-select>
<!-- 拖拽时的遮罩 -->
<div class="go-edit-range-model" :style="rangeModelStyle"></div>
</div>
@@ -15,11 +17,13 @@
<script setup lang="ts">
import { toRefs, computed } from 'vue'
import { useSizeStyle } from '../../hooks/useStyle.hook'
import { mousedownHandleUnStop } from '../../hooks/useDrag.hook'
import { canvasModelIndex } from '@/settings/designSetting'
import { mousedownBoxSelect } from '../../hooks/useDrag.hook'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditAlignLine } from '../EditAlignLine'
import { EditWatermark } from '../EditWatermark'
import { EditRule } from '../EditRule'
import { EditSelect } from '../EditSelect'
const chartEditStore = useChartEditStore()
@@ -11,13 +11,12 @@
</template>
<script setup lang="ts">
import { ref, toRefs } from 'vue'
import { toRefs, computed } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useDesignStore } from '@/store/modules/designStore/designStore'
const chartEditStore = useChartEditStore()
const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const { width, height } = toRefs(chartEditStore.getEditCanvasConfig)
@@ -34,6 +33,12 @@ const lines = {
h: [],
v: []
}
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
</script>
<style>
@@ -0,0 +1,3 @@
import EditSelect from './index.vue'
export { EditSelect }
@@ -0,0 +1,111 @@
<template>
<div class="go-edit-select" v-if="isSelect" :style="positionStyle">
<div class="select-background"></div>
<div class="select-border"></div>
</div>
</template>
<script setup lang="ts">
import { ref, toRefs, watch, computed } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { useSizeStyle, useComponentStyle } from '../../hooks/useStyle.hook'
import { selectBoxIndex } from '@/settings/designSetting'
// 全局颜色
const designStore = useDesignStore()
const chartEditStore = useChartEditStore()
const { isSelect, scale } = toRefs(chartEditStore.getEditCanvas)
const themeColor = computed(() => {
return designStore.getAppTheme
})
// 位置
const positionStyle = ref()
watch(
() => chartEditStore.getMousePosition,
positionInfo => {
if (!isSelect.value) return
// 这里的 x,y 是已经计算过的相对位移值
const { startX, startY, x, y } = positionInfo
const attr = {
zIndex: selectBoxIndex,
// left
x: 0,
// top
y: 0,
// 宽
w: 0,
// 高
h: 0
}
// 处理位置
if (x > startX && y > startY) {
// 右下方向
attr.x = startX
attr.y = startY
attr.w = Math.round((x - startX) / scale.value)
attr.h = Math.round((y - startY) / scale.value)
} else if (x > startX && y < startY) {
// 右上方向
attr.x = startX
attr.w = Math.round((x - startX) / scale.value)
attr.h = Math.round((startY - y) / scale.value)
attr.y = startY - attr.h
} else if (x < startX && y > startY) {
// 左下方向
attr.y = startY
attr.w = Math.round((startX - x) / scale.value)
attr.h = Math.round((y - startY) / scale.value)
attr.x = startX - attr.w
} else {
// 左上方向
attr.w = Math.round((startX - x) / scale.value)
attr.h = Math.round((startY - y) / scale.value)
attr.x = startX - attr.w
attr.y = startY - attr.h
}
positionStyle.value = {
...useComponentStyle(attr, selectBoxIndex),
...useSizeStyle(attr)
}
},
{
deep: true
}
)
</script>
<style lang="scss" scoped>
@include go('edit-select') {
position: absolute;
.select-border,
.select-background {
position: absolute;
width: 100%;
height: 100%;
border-radius: 10px;
overflow: hidden;
}
.select-border {
left: 0;
top: 0;
opacity: 0.5;
border-width: 2px;
border-style: solid;
border-color: v-bind('themeColor');
}
.select-background {
top: 2px;
left: 2px;
opacity: 0.03;
background-color: v-bind('themeColor');
}
}
</style>
@@ -2,13 +2,15 @@
<div class="go-shape-box">
<slot></slot>
<!-- 锚点 -->
<div
:class="`shape-point ${point}`"
v-for="(point, index) in select ? pointList : []"
:key="index"
:style="usePointStyle(point, index, item.attr, cursorResize)"
@mousedown="useMousePointHandle($event, point, item.attr)"
></div>
<template v-if="!hiddenPoint">
<div
:class="`shape-point ${point}`"
v-for="(point, index) in select ? pointList : []"
:key="index"
:style="usePointStyle(point, index, item.attr, cursorResize)"
@mousedown="useMousePointHandle($event, point, item.attr)"
></div>
</template>
<!-- 选中 -->
<div class="shape-modal" :style="useSizeStyle(item.attr)">
@@ -19,23 +21,25 @@
</template>
<script setup lang="ts">
import { ref, computed, PropType, toRefs } from 'vue'
import { computed, PropType } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { CreateComponentType } from '@/packages/index.d'
import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { useSizeStyle, usePointStyle } from '../../hooks/useStyle.hook'
import { useMousePointHandle } from '../../hooks/useDrag.hook'
const props = defineProps({
item: {
type: Object as PropType<CreateComponentType>,
type: Object as PropType<CreateComponentType | CreateComponentGroupType>,
required: true
},
hiddenPoint: {
type: Boolean,
required: false
}
})
// 全局颜色
const designStore = useDesignStore()
const themeColor = ref(designStore.getAppTheme)
const chartEditStore = useChartEditStore()
// 锚点
@@ -44,6 +48,11 @@ const pointList = ['t', 'r', 'b', 'l', 'lt', 'rt', 'lb', 'rb']
// 光标朝向
const cursorResize = ['n', 'e', 's', 'w', 'nw', 'ne', 'sw', 'se']
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme
})
// 计算当前选中目标
const hover = computed(() => {
return props.item.id === chartEditStore.getTargetChart.hoverId
@@ -1,9 +1,5 @@
<template>
<n-modal
v-model:show="modelShow"
:mask-closable="true"
@afterLeave="closeHandle"
>
<n-modal v-model:show="modelShow" :mask-closable="true" @afterLeave="closeHandle">
<n-table class="model-content" :bordered="false" :single-line="false">
<thead>
<tr>
@@ -24,9 +20,7 @@
<td>{{ item.label }}</td>
<td>{{ item.win }}</td>
<td>
<n-gradient-text :size="22">{{
item.mac.substr(0, 1)
}}</n-gradient-text>
<n-gradient-text :size="22">{{ item.mac.substr(0, 1) }}</n-gradient-text>
+ {{ item.mac.substr(3) }}
</td>
</tr>
@@ -44,7 +38,7 @@ const { CloseIcon } = icon.ionicons5
const emit = defineEmits(['update:modelShow'])
defineProps({
modelShow: Boolean,
modelShow: Boolean
})
// 快捷键
@@ -52,58 +46,73 @@ const shortcutKeyOptions = [
{
label: '向上移动',
win: `${WinKeyboard.CTRL.toUpperCase()} + ↑ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ↑ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ↑ `
},
{
label: '向右移动',
win: `${WinKeyboard.CTRL.toUpperCase()} + → `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + → `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + → `
},
{
label: '向下移动',
win: `${WinKeyboard.CTRL.toUpperCase()} + ↓ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ↓ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ↓ `
},
{
label: '向左移动',
win: `${WinKeyboard.CTRL.toUpperCase()} + ← `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ← `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ← `
},
{
label: '删除',
win: 'Delete'.toUpperCase(),
mac: `${MacKeyboard.CTRL.toUpperCase()} + Backspace `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + Backspace `
},
{
label: '复制',
win: `${WinKeyboard.CTRL.toUpperCase()} + C `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + C `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + C `
},
{
label: '剪切',
win: `${WinKeyboard.CTRL.toUpperCase()} + X `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + X `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + X `
},
{
label: '粘贴',
win: `${WinKeyboard.CTRL.toUpperCase()} + V `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + V `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + V `
},
{
label: '后退',
win: `${WinKeyboard.CTRL.toUpperCase()} + Z `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + Z `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + Z `
},
{
label: '前进',
win: `${WinKeyboard.CTRL.toUpperCase()} + ${WinKeyboard.SHIFT.toUpperCase()} + Z `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ${MacKeyboard.SHIFT.toUpperCase()} + Z `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ${MacKeyboard.SHIFT.toUpperCase()} + Z `
},
{
label: '保存',
win: `${WinKeyboard.CTRL.toUpperCase()} + S `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + S `,
},
{
label: '多选',
win: `${WinKeyboard.CTRL.toUpperCase()} + 🖱️ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + 🖱️ `
},
{
label: '创建分组',
win: `${WinKeyboard.CTRL.toUpperCase()} + G / 🖱️ `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + G / 🖱️`
},
{
label: '解除分组',
win: `${WinKeyboard.CTRL.toUpperCase()} + ${WinKeyboard.SHIFT.toUpperCase()} + G `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ${WinKeyboard.SHIFT.toUpperCase()} + G `
}
]
const closeHandle = () => {
emit('update:modelShow', false)
@@ -120,4 +129,4 @@ const closeHandle = () => {
padding: 5px 10px;
}
}
</style>
</style>
@@ -31,15 +31,15 @@ export const useFile = () => {
negativeText: '覆盖(不可撤回)',
negativeButtonProps: { type: 'info', ghost: false },
// 新增
onNegativeCallback: async () => {
onPositiveCallback: async () => {
fileData = JSON.parse(fileData)
await updateComponent(fileData, true)
await updateComponent(fileData, false, true)
window['$message'].success('导入成功!')
},
// 覆盖
onPositiveCallback: async () => {
onNegativeCallback: async () => {
fileData = JSON.parse(fileData)
await updateComponent(fileData)
await updateComponent(fileData, true, true)
window['$message'].success('导入成功!')
}
})
+197 -50
View File
@@ -1,10 +1,8 @@
import { DragKeyEnum } from '@/enums/editPageEnum'
import { toRaw } from 'vue'
import { DragKeyEnum, MouseEventButton, WinKeyboard, MacKeyboard } from '@/enums/editPageEnum'
import { createComponent } from '@/packages'
import { ConfigType } from '@/packages/index.d'
import {
CreateComponentType,
PickCreateComponentType,
} from '@/packages/index.d'
import { CreateComponentType, CreateComponentGroupType, PickCreateComponentType } from '@/packages/index.d'
import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
@@ -22,7 +20,7 @@ export const dragHandle = async (e: DragEvent) => {
loadingStart()
// 获取拖拽数据
const drayDataString = e!.dataTransfer!.getData(DragKeyEnum.DROG_KEY)
const drayDataString = e!.dataTransfer!.getData(DragKeyEnum.DRAG_KEY)
if (!drayDataString) {
loadingFinish()
return
@@ -35,10 +33,7 @@ export const dragHandle = async (e: DragEvent) => {
// 创建新图表组件
let newComponent: CreateComponentType = await createComponent(dropData)
newComponent.setPosition(
e.offsetX - newComponent.attr.w / 2,
e.offsetY - newComponent.attr.h / 2
)
newComponent.setPosition(e.offsetX - newComponent.attr.w / 2, e.offsetY - newComponent.attr.h / 2)
chartEditStore.addComponentList(newComponent, false, true)
chartEditStore.setTargetSelectChart(newComponent.id)
loadingFinish()
@@ -57,10 +52,7 @@ export const dragoverHandle = (e: DragEvent) => {
}
// * 不拦截默认行为点击
export const mousedownHandleUnStop = (
e: MouseEvent,
item?: CreateComponentType
) => {
export const mousedownHandleUnStop = (e: MouseEvent, item?: CreateComponentType | CreateComponentGroupType) => {
if (item) {
chartEditStore.setTargetSelectChart(item.id)
return
@@ -68,56 +60,213 @@ export const mousedownHandleUnStop = (
chartEditStore.setTargetSelectChart(undefined)
}
// * 移动图表
// * 框选
export const mousedownBoxSelect = (e: MouseEvent, item?: CreateComponentType | CreateComponentGroupType) => {
mousedownHandleUnStop(e)
// 记录点击初始位置
const startOffsetX = e.offsetX
const startOffsetY = e.offsetY
const startScreenX = e.screenX
const startScreenY = e.screenY
// 记录缩放
const scale = chartEditStore.getEditCanvas.scale
chartEditStore.setMousePosition(undefined, undefined, startOffsetX, startOffsetY)
// 移动框选
const mousemove = throttle((moveEvent: MouseEvent) => {
// 取消当前选中
chartEditStore.setTargetSelectChart()
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_SELECT, true)
// 这里先把相对值算好,不然组件无法获取 startScreenX 和 startScreenY 的值
const currX = startOffsetX + moveEvent.screenX - startScreenX
const currY = startOffsetY + moveEvent.screenY - startScreenY
chartEditStore.setMousePosition(currX, currY)
// 计算框选的左上角和右下角
const selectAttr = {
// 左上角
x1: 0,
y1: 0,
// 右下角
x2: 0,
y2: 0
}
if (currX > startOffsetX && currY > startOffsetY) {
// 右下方向
selectAttr.x1 = startOffsetX
selectAttr.y1 = startOffsetY
selectAttr.x2 = Math.round(startOffsetX + (moveEvent.screenX - startScreenX) / scale)
selectAttr.y2 = Math.round(startOffsetY + (moveEvent.screenY - startScreenY) / scale)
} else if (currX > startOffsetX && currY < startOffsetY) {
// 右上方向
selectAttr.x1 = startOffsetX
selectAttr.y1 = Math.round(startOffsetY - (startScreenY - moveEvent.screenY) / scale)
selectAttr.x2 = Math.round(startOffsetX + (moveEvent.screenX - startScreenX) / scale)
selectAttr.y2 = startOffsetY
} else if (currX < startOffsetX && currY > startOffsetY) {
selectAttr.x1 = Math.round(startOffsetX - (startScreenX - moveEvent.screenX) / scale)
selectAttr.y1 = startOffsetY
selectAttr.x2 = startOffsetX
selectAttr.y2 = Math.round(startOffsetY + (moveEvent.screenY - startScreenY ) / scale)
// 左下方向
} else {
// 左上方向
selectAttr.x1 = Math.round(startOffsetX - (startScreenX - moveEvent.screenX) / scale)
selectAttr.y1 = Math.round(startOffsetY - (startScreenY - moveEvent.screenY) / scale)
selectAttr.x2 = startOffsetX
selectAttr.y2 = startOffsetY
}
// 遍历组件
chartEditStore.getComponentList.forEach(item => {
if (!chartEditStore.getTargetChart.selectId.includes(item.id)) {
// 处理左上角
let isSelect = false
const { x, y, w, h } = item.attr
const targetAttr = {
// 左上角
x1: x,
y1: y,
// 右下角
x2: x + w,
y2: y + h
}
// 全包含则选中
if (
targetAttr.x1 - selectAttr.x1 >= 0 &&
targetAttr.y1 - selectAttr.y1 >= 0 &&
targetAttr.x2 - selectAttr.x2 <= 0 &&
targetAttr.y2 - selectAttr.y2 <= 0
) {
isSelect = true
chartEditStore.setTargetSelectChart(item.id, true)
}
}
})
}, 20)
// 鼠标抬起
const mouseup = () => {
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_SELECT, false)
chartEditStore.setMousePosition(0, 0, 0, 0)
document.removeEventListener('mousemove', mousemove)
document.removeEventListener('mouseup', mouseup)
}
document.addEventListener('mousemove', mousemove)
document.addEventListener('mouseup', mouseup)
}
// * 鼠标事件
export const useMouseHandle = () => {
// 点击事件(包含移动事件)
const mousedownHandle = (e: MouseEvent, item: CreateComponentType) => {
// * Click 事件, 松开鼠标触发
const mouseClickHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
e.preventDefault()
e.stopPropagation()
// 若此时按下了 CTRL, 表示多选
if (
window.$KeyboardActive?.has(WinKeyboard.CTRL_SOURCE_KEY) ||
window.$KeyboardActive?.has(MacKeyboard.CTRL_SOURCE_KEY)
) {
// 若已选中,则去除
if (chartEditStore.targetChart.selectId.includes(item.id)) {
const exList = chartEditStore.targetChart.selectId.filter(e => e !== item.id)
chartEditStore.setTargetSelectChart(exList)
} else {
chartEditStore.setTargetSelectChart(item.id, true)
}
}
}
// * 按下事件(包含移动事件)
const mousedownHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
e.preventDefault()
e.stopPropagation()
onClickOutSide()
// 按下左键 + CTRL
if (
e.buttons === MouseEventButton.LEFT &&
(window.$KeyboardActive?.has(WinKeyboard.CTRL_SOURCE_KEY) ||
window.$KeyboardActive?.has(MacKeyboard.CTRL_SOURCE_KEY))
)
return
// 按下右键 + 选中多个 + 目标元素是多选子元素
const selectId = chartEditStore.getTargetChart.selectId
if (e.buttons === MouseEventButton.RIGHT && selectId.length > 1 && selectId.includes(item.id)) return
// 选中当前目标组件
chartEditStore.setTargetSelectChart(item.id)
// 按下右键
if (e.buttons === MouseEventButton.RIGHT) return
const scale = chartEditStore.getEditCanvas.scale
const width = chartEditStore.getEditCanvasConfig.width
const height = chartEditStore.getEditCanvasConfig.height
const canvasWidth = chartEditStore.getEditCanvasConfig.width
const canvasHeight = chartEditStore.getEditCanvasConfig.height
// 记录图表初始位置和大小
const itemAttrX = item.attr.x
const itemAttrY = item.attr.y
const itemAttrW = item.attr.w
const itemAttrH = item.attr.h
const targetMap = new Map()
chartEditStore.getTargetChart.selectId.forEach(id => {
const index = chartEditStore.fetchTargetIndex(id)
if (index !== -1) {
const { x, y, w, h } = toRaw(chartEditStore.getComponentList[index]).attr
targetMap.set(id, { x, y, w, h })
}
})
// 记录点击初始位置
const startX = e.screenX
const startY = e.screenY
// 记录初始位置
chartEditStore.setMousePosition(startX, startY)
// 计算偏移量(处理 scale 比例问题)
// 记录初始位置
chartEditStore.setMousePosition(undefined, undefined, startX, startY)
// 移动-计算偏移量
const mousemove = throttle((moveEvent: MouseEvent) => {
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, true)
chartEditStore.setMousePosition(moveEvent.screenX, moveEvent.screenY)
let currX = Math.round(itemAttrX + (moveEvent.screenX - startX) / scale)
let currY = Math.round(itemAttrY + (moveEvent.screenY - startY) / scale)
// 当前偏移量,处理 scale 比例问题
let offsetX = (moveEvent.screenX - startX) / scale
let offsetY = (moveEvent.screenY - startY) / scale
// 要预留的距离
const distance = 50
// 基于左上角位置检测
currX = currX < -itemAttrW + distance ? -itemAttrW + distance : currX
currY = currY < -itemAttrH + distance ? -itemAttrH + distance : currY
chartEditStore.getTargetChart.selectId.forEach(id => {
if (!targetMap.has(id)) return
// 基于右下角位置检测
currX = currX > width - distance ? width - distance : currX
currY = currY > height - distance ? height - distance : currY
const index = chartEditStore.fetchTargetIndex(id)
// 拿到初始位置数据
const { x, y, w, h } = targetMap.get(id)
const componentInstance = chartEditStore.getComponentList[index]
item.attr.x = currX
item.attr.y = currY
}, 30)
let currX = Math.round(x + offsetX)
let currY = Math.round(y + offsetY)
// 要预留的距离
const distance = 50
// 基于左上角位置检测
currX = currX < -w + distance ? -w + distance : currX
currY = currY < -h + distance ? -h + distance : currY
// 基于右下角位置检测
currX = currX > canvasWidth - distance ? canvasWidth - distance : currX
currY = currY > canvasHeight - distance ? canvasHeight - distance : currY
componentInstance.attr = Object.assign(componentInstance.attr, {
x: currX,
y: currY
})
})
return
}, 20)
const mouseup = () => {
chartEditStore.setMousePosition(0, 0, 0, 0)
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false)
chartEditStore.setMousePosition(0, 0)
document.removeEventListener('mousemove', mousemove)
document.removeEventListener('mouseup', mouseup)
}
@@ -127,29 +276,27 @@ export const useMouseHandle = () => {
}
// * 进入事件
const mouseenterHandle = (e: MouseEvent, item: CreateComponentType) => {
const mouseenterHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
e.preventDefault()
e.stopPropagation()
chartEditStore.setTargetHoverChart(item.id)
if (!chartEditStore.getEditCanvas.isSelect) {
chartEditStore.setTargetHoverChart(item.id)
}
}
// * 移出事件
const mouseleaveHandle = (e: MouseEvent, item: CreateComponentType) => {
const mouseleaveHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
e.preventDefault()
e.stopPropagation()
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false)
chartEditStore.setTargetHoverChart(undefined)
}
return { mousedownHandle, mouseenterHandle, mouseleaveHandle }
return { mouseClickHandle, mousedownHandle, mouseenterHandle, mouseleaveHandle }
}
// * 移动锚点
export const useMousePointHandle = (
e: MouseEvent,
point: string,
attr: PickCreateComponentType<'attr'>
) => {
export const useMousePointHandle = (e: MouseEvent, point: string, attr: PickCreateComponentType<'attr'>) => {
e.stopPropagation()
e.preventDefault()
@@ -191,7 +338,7 @@ export const useMousePointHandle = (
const mouseup = () => {
chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false)
chartEditStore.setMousePosition(0, 0)
chartEditStore.setMousePosition(0, 0, 0, 0)
document.removeEventListener('mousemove', mousemove)
document.removeEventListener('mouseup', mouseup)
}
+67 -29
View File
@@ -15,37 +15,45 @@
<!-- 展示 -->
<edit-range>
<!-- 滤镜预览 -->
<div :style="{
<div
:style="{
...getFilterStyle(chartEditStore.getEditCanvasConfig),
...rangeStyle
}">
}"
>
<!-- 图表 -->
<edit-shape-box
v-for="(item, index) in chartEditStore.getComponentList"
:key="item.id"
:data-id="item.id"
:index="index"
:style="useComponentStyle(item.attr, index)"
:item="item"
@mousedown="mousedownHandle($event, item)"
@mouseenter="mouseenterHandle($event, item)"
@mouseleave="mouseleaveHandle($event, item)"
@contextmenu="handleContextMenu($event, item)"
>
<component
class="edit-content-chart"
:class="animationsClass(item.styles.animations)"
:is="item.chartConfig.chartKey"
:chartConfig="item"
:themeSetting="themeSetting"
:themeColor="themeColor"
:style="{
...useSizeStyle(item.attr),
...getFilterStyle(item.styles),
...getTransformStyle(item.styles),
}"
></component>
</edit-shape-box>
<div v-for="(item, index) in chartEditStore.getComponentList" :key="item.id">
<!-- 分组 -->
<edit-group v-if="item.isGroup" :groupData="(item as CreateComponentGroupType)" :groupIndex="index"></edit-group>
<!-- 单组件 -->
<edit-shape-box
v-else
:data-id="item.id"
:index="index"
:style="useComponentStyle(item.attr, index)"
:item="item"
@click="mouseClickHandle($event, item)"
@mousedown="mousedownHandle($event, item)"
@mouseenter="mouseenterHandle($event, item)"
@mouseleave="mouseleaveHandle($event, item)"
@contextmenu="handleContextMenu($event, item, optionsHandle)"
>
<component
class="edit-content-chart"
:class="animationsClass(item.styles.animations)"
:is="item.chartConfig.chartKey"
:chartConfig="item"
:themeSetting="themeSetting"
:themeColor="themeColor"
:style="{
...useSizeStyle(item.attr),
...getFilterStyle(item.styles),
...getTransformStyle(item.styles)
}"
></component>
</edit-shape-box>
</div>
</div>
</edit-range>
</div>
@@ -65,8 +73,11 @@
<script lang="ts" setup>
import { onMounted, computed } from 'vue'
import { chartColors } from '@/settings/chartThemes/index'
import { MenuEnum } from '@/enums/editPageEnum'
import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
import { animationsClass, getFilterStyle, getTransformStyle } from '@/utils'
import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook'
import { MenuOptionsItemType } from '@/views/chart/hooks/useContextMenu.hook.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useLayout } from './hooks/useLayout.hook'
@@ -76,6 +87,7 @@ import { dragHandle, dragoverHandle, useMouseHandle } from './hooks/useDrag.hook
import { useComponentStyle, useSizeStyle } from './hooks/useStyle.hook'
import { ContentBox } from '../ContentBox/index'
import { EditGroup } from './components/EditGroup'
import { EditRange } from './components/EditRange'
import { EditBottom } from './components/EditBottom'
import { EditShapeBox } from './components/EditShapeBox'
@@ -89,7 +101,33 @@ const { dataSyncFetch, intervalDataSyncUpdate } = useSync()
useLayout()
// 点击事件
const { mouseenterHandle, mouseleaveHandle, mousedownHandle } = useMouseHandle()
const { mouseenterHandle, mouseleaveHandle, mousedownHandle, mouseClickHandle } = useMouseHandle()
// 右键事件
const optionsHandle = (
targetList: MenuOptionsItemType[],
allList: MenuOptionsItemType[],
targetInstance: CreateComponentType
) => {
// 多选
const moreMenuEnums = [MenuEnum.GROUP, MenuEnum.DELETE]
// 单选
const singleMenuEnums = targetList
// 多选处理
if (chartEditStore.getTargetChart.selectId.length > 1) {
const list: MenuOptionsItemType[] = []
allList.forEach(item => {
// 成组
if (moreMenuEnums.includes(item.key as MenuEnum)) {
list.push(item)
}
})
return list
}
return singleMenuEnums
}
// 主题色
const themeSetting = computed(() => {