feat: 右键菜单

Re-1.0
咬轮猫 3 years ago
parent 8209dae48e
commit feb6f31d69

@ -39,6 +39,7 @@
@mousedown="onSvgMouseDown(item, index, $event)" @mousedown="onSvgMouseDown(item, index, $event)"
@mouseenter="onSvgMouseEnter(item, index, $event)" @mouseenter="onSvgMouseEnter(item, index, $event)"
@mouseleave="onSvgMouseLeave(item, index, $event)" @mouseleave="onSvgMouseLeave(item, index, $event)"
@contextmenu="onSvgContextMenuEvent(item, index, $event)"
> >
<connection-line <connection-line
v-if="item.type === EDoneJsonType.ConnectionLine" v-if="item.type === EDoneJsonType.ConnectionLine"
@ -155,10 +156,23 @@
</g> </g>
</g> </g>
</svg> </svg>
<!-- 右键菜单 -->
<ul ref="contextMenuRef" class="contextMenu" v-show="contextMenuStore.display">
<li
v-for="(item, key) in contextMenuStore.info"
:key="item.title"
@click="contextMenuStore.onContextMenuClick(key)"
>
<p :class="item.enable ? '' : 'disabled'">
{{ item.title }}
<span class="shortcut">{{ item.hot_key }}</span>
</p>
</li>
</ul>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, getCurrentInstance, onMounted, reactive } from 'vue'; import { computed, getCurrentInstance, onMounted, reactive, ref } from 'vue';
import { useConfigStore } from '@/store/config'; import { useConfigStore } from '@/store/config';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/store/global';
import { import {
@ -192,6 +206,7 @@
import ConnectionLine from '@/components/webtopo-svgedit/components/connection-line/index.vue'; import ConnectionLine from '@/components/webtopo-svgedit/components/connection-line/index.vue';
import { IVisiableInfo } from './types'; import { IVisiableInfo } from './types';
import { ComponentImport } from '@/config-center'; import { ComponentImport } from '@/config-center';
import { useContextMenuStore } from '@/store/system';
// import HandlePanel from '../handle-panel/index.vue'; // import HandlePanel from '../handle-panel/index.vue';
// //
const instance = getCurrentInstance(); const instance = getCurrentInstance();
@ -203,6 +218,8 @@
const globalStore = useGlobalStore(); const globalStore = useGlobalStore();
const configStore = useConfigStore(); const configStore = useConfigStore();
const svgEditLayoutStore = useSvgEditLayoutStore(); const svgEditLayoutStore = useSvgEditLayoutStore();
const contextMenuStore = useContextMenuStore();
const contextMenuRef = ref<HTMLElement>();
const cursor_style = computed(() => const cursor_style = computed(() =>
globalStore.intention == EGlobalStoreIntention.MoveCanvas globalStore.intention == EGlobalStoreIntention.MoveCanvas
? 'grab' ? 'grab'
@ -299,7 +316,6 @@
e.preventDefault(); e.preventDefault();
}; };
const onSvgMouseDown = (select_item: IDoneJson, index: number, e: MouseEvent) => { const onSvgMouseDown = (select_item: IDoneJson, index: number, e: MouseEvent) => {
console.log('触发选中', e);
if (globalStore.intention === EGlobalStoreIntention.Connection) { if (globalStore.intention === EGlobalStoreIntention.Connection) {
return; return;
} }
@ -613,9 +629,9 @@
new_position_x: 0, new_position_x: 0,
new_position_y: 0 new_position_y: 0
}); });
contextMenuStore.display = false;
}; };
const onCanvasMouseDown = (e: MouseEvent) => { const onCanvasMouseDown = (e: MouseEvent) => {
console.log('onCanvasMouseDown', e);
const { clientX, clientY } = e; const { clientX, clientY } = e;
if (globalStore.intention === EGlobalStoreIntention.Connection && globalStore.handle_svg_info) { if (globalStore.intention === EGlobalStoreIntention.Connection && globalStore.handle_svg_info) {
if (e.button === 0) { if (e.button === 0) {
@ -661,6 +677,32 @@
const onCanvasContextMenuEvent = (e: MouseEvent) => { const onCanvasContextMenuEvent = (e: MouseEvent) => {
e.preventDefault(); // e.preventDefault(); //
}; };
const onSvgContextMenuEvent = (select_item: IDoneJson, index: number, e: MouseEvent) => {
if (globalStore.intention === EGlobalStoreIntention.Connection) {
return;
}
if (contextMenuRef.value) {
globalStore.intention = EGlobalStoreIntention.ContextMenu;
globalStore.setHandleSvgInfo(select_item, index);
contextMenuRef.value.style.left = e.pageX + 'px';
contextMenuRef.value.style.top = e.pageY + 'px';
contextMenuStore.info.MoveUpOneLevel.enable =
contextMenuStore.info.MoveUpTopLevel.enable =
contextMenuStore.info.MoveDownOneLevel.enable =
contextMenuStore.info.MoveDownTopLevel.enable =
true;
if (index === globalStore.done_json.length - 1) {
contextMenuStore.info.MoveUpOneLevel.enable = contextMenuStore.info.MoveUpTopLevel.enable =
false;
}
if (index === 0) {
contextMenuStore.info.MoveDownOneLevel.enable =
contextMenuStore.info.MoveDownTopLevel.enable = false;
}
contextMenuStore.display = true;
}
};
const getActualBoundScale = ( const getActualBoundScale = (
actual_bound: { actual_bound: {
x: number; x: number;
@ -678,6 +720,7 @@
height: actual_bound.height * scale_y height: actual_bound.height * scale_y
}; };
}; };
onMounted(() => { onMounted(() => {
globalStore.setDoneJson([]); globalStore.setDoneJson([]);
}); });
@ -706,4 +749,56 @@
cursor: move; cursor: move;
outline: 1px solid rgb(23, 222, 30); outline: 1px solid rgb(23, 222, 30);
} }
.contextMenu {
position: absolute;
z-index: 99999;
background: #ffffff;
padding: 5px 0;
margin: 0px;
display: block;
border-radius: 5px;
box-shadow: 2px 5px 10px rgba(0, 0, 0, 0.3);
li {
list-style: none;
padding: 0px;
margin: 0px;
}
.shortcut {
width: 115px;
text-align: right;
float: right;
}
p {
text-decoration: none;
display: block;
padding: 0px 15px 1px 20px;
margin: 0;
user-select: none;
-webkit-user-select: none;
}
p:hover {
background-color: #0cf;
color: #ffffff;
cursor: default;
}
.disabled {
color: #999;
}
.disabled:hover {
color: #999;
background-color: transparent;
}
li.separator {
border-top: solid 1px #e3e3e3;
padding-top: 5px;
margin-top: 5px;
}
}
</style> </style>

@ -63,8 +63,6 @@
const libChange = (val: any) => { const libChange = (val: any) => {
config_center.value = []; config_center.value = [];
config_center.value = val; config_center.value = val;
console.log(val, 71474);
}; };
const createBegin = (svg_item: IConfigItem) => { const createBegin = (svg_item: IConfigItem) => {

@ -14,13 +14,14 @@
<el-form-item label="y轴原点坐标" size="small"> <el-form-item label="y轴原点坐标" size="small">
<el-input-number v-model="configStore.svg.position_center.y"></el-input-number> <el-input-number v-model="configStore.svg.position_center.y"></el-input-number>
</el-form-item> </el-form-item>
<el-form-item label="缩放" size="small"> <!-- 基础版不做画布缩放了 有需要自己写吧^-^ -->
<!-- <el-form-item label="缩放" size="small">
<el-input-number <el-input-number
v-model="configStore.svg.scale" v-model="configStore.svg.scale"
:step="0.1" :step="0.1"
step-strictly step-strictly
></el-input-number> ></el-input-number>
</el-form-item> </el-form-item> -->
</el-form> </el-form>
</div> </div>
</div> </div>

@ -0,0 +1,18 @@
import { IDoneJson } from '@/store/global/types';
import { useEditPrivateStore } from '@/store/system';
export const useHistoryRecord = (done_json: IDoneJson[]) => {
const edit_private_store = useEditPrivateStore();
if (edit_private_store.is_record_history) {
if (edit_private_store.history_nowindex + 1 < edit_private_store.history_doneComponent.length) {
edit_private_store.history_doneComponent.splice(edit_private_store.history_nowindex + 1);
}
edit_private_store.history_doneComponent.push(done_json);
edit_private_store.history_nowindex = edit_private_store.history_doneComponent.length - 1;
if (edit_private_store.history_doneComponent.length > edit_private_store.max_record_times) {
edit_private_store.history_doneComponent.shift();
edit_private_store.history_nowindex = edit_private_store.history_doneComponent.length - 1;
}
}
edit_private_store.is_record_history = true;
};

@ -12,7 +12,7 @@ import {
IMouseInfo, IMouseInfo,
IScaleInfo IScaleInfo
} from './types'; } from './types';
import { useEditPrivateStore } from '../system'; import { useHistoryRecord } from '@/hooks';
/** /**
* *
*/ */
@ -67,7 +67,6 @@ export const useGlobalStore = defineStore('global-store', {
this.create_svg_info = create_svg_info; this.create_svg_info = create_svg_info;
}, },
setDoneJson(done_json: IDoneJson[] | IDoneJson) { setDoneJson(done_json: IDoneJson[] | IDoneJson) {
console.log('这里要记录操作历史记录', done_json);
if (isOfType(done_json, 'id')) { if (isOfType(done_json, 'id')) {
this.done_json.push(done_json); this.done_json.push(done_json);
nextTick(() => { nextTick(() => {
@ -77,29 +76,7 @@ export const useGlobalStore = defineStore('global-store', {
this.done_json = objectDeepClone<IDoneJson[]>(done_json); this.done_json = objectDeepClone<IDoneJson[]>(done_json);
} }
nextTick(() => { nextTick(() => {
const edit_private_store = useEditPrivateStore(); useHistoryRecord(objectDeepClone<IDoneJson[]>(this.done_json));
if (edit_private_store.is_record_history) {
if (
edit_private_store.history_nowindex + 1 <
edit_private_store.history_doneComponent.length
) {
edit_private_store.history_doneComponent.splice(
edit_private_store.history_nowindex + 1
);
}
edit_private_store.history_doneComponent.push(
objectDeepClone<IDoneJson[]>(this.done_json)
);
edit_private_store.history_nowindex = edit_private_store.history_doneComponent.length - 1;
if (
edit_private_store.history_doneComponent.length > edit_private_store.max_record_times
) {
edit_private_store.history_doneComponent.shift();
edit_private_store.history_nowindex =
edit_private_store.history_doneComponent.length - 1;
}
}
edit_private_store.is_record_history = true;
}); });
}, },
setMouseInfo(mouse_info: IMouseInfo) { setMouseInfo(mouse_info: IMouseInfo) {
@ -122,6 +99,11 @@ export const useGlobalStore = defineStore('global-store', {
}, },
setScaleInfo(info: IScaleInfo) { setScaleInfo(info: IScaleInfo) {
this.scale_info = info; this.scale_info = info;
},
spliceDoneJson(index: number) {
const globalStore = useGlobalStore();
globalStore.done_json.splice(index, 1);
useHistoryRecord(globalStore.done_json);
} }
} }
}); });

@ -45,7 +45,8 @@ export enum EGlobalStoreIntention {
Zoom = 'Zoom', Zoom = 'Zoom',
Rotate = 'Rotate', Rotate = 'Rotate',
Connection = 'Connection', Connection = 'Connection',
SetConnectionLineNode = 'SetConnectionLineNode' SetConnectionLineNode = 'SetConnectionLineNode',
ContextMenu = 'ContextMenu'
} }
export interface IMouseInfo { export interface IMouseInfo {
state: EMouseInfoState; state: EMouseInfoState;

@ -1,7 +1,9 @@
import { objectDeepClone, randomString } from '@/utils';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { useGlobalStore } from '../global'; import { useGlobalStore } from '../global';
import { EditPrivateStoreState } from './types'; import { IDoneJson } from '../global/types';
import { ContextMenuStoreState, EContextMenuInfoType, EditPrivateStoreState } from './types';
import { useHistoryRecord } from '@/hooks';
/** /**
* *
*/ */
@ -53,3 +55,115 @@ export const useEditPrivateStore = defineStore('edit-private-store', {
} }
} }
}); });
export const useContextMenuStore = defineStore('context-menu-store', {
state: (): ContextMenuStoreState => {
return {
display: false,
info: {
[EContextMenuInfoType.Copy]: {
title: '复制',
hot_key: 'Ctrl+C',
enable: true
},
[EContextMenuInfoType.Delete]: {
title: '删除',
hot_key: 'Delete',
enable: true
},
[EContextMenuInfoType.MoveUpTopLevel]: {
title: '置于顶层',
hot_key: 'Ctrl+→',
enable: true
},
[EContextMenuInfoType.MoveDownTopLevel]: {
title: '置于底层',
hot_key: 'Ctrl+←',
enable: true
},
[EContextMenuInfoType.MoveUpOneLevel]: {
title: '置于上一层',
hot_key: 'Ctrl+↑',
enable: true
},
[EContextMenuInfoType.MoveDownOneLevel]: {
title: '置于下一层',
hot_key: 'Ctrl+↓',
enable: true
}
}
};
},
actions: {
onContextMenuClick(type: EContextMenuInfoType) {
const globalStore = useGlobalStore();
if (!globalStore.handle_svg_info) {
return;
}
switch (type) {
case EContextMenuInfoType.Copy:
const temp_item = objectDeepClone<IDoneJson>(globalStore.handle_svg_info.info);
temp_item.id = temp_item.name + randomString();
temp_item.title += '-copy';
temp_item.x += 10;
temp_item.y += 10;
globalStore.setDoneJson(temp_item);
this.display = false;
break;
case EContextMenuInfoType.Delete:
globalStore.spliceDoneJson(globalStore.handle_svg_info.index);
this.display = false;
break;
case EContextMenuInfoType.MoveUpOneLevel:
if (
globalStore.done_json.length === 1 ||
globalStore.handle_svg_info.index === globalStore.done_json.length - 1
) {
return;
}
const temp_up_one = globalStore.handle_svg_info.info;
globalStore.done_json[globalStore.handle_svg_info.index] =
globalStore.done_json[globalStore.handle_svg_info.index + 1];
globalStore.done_json[globalStore.handle_svg_info.index + 1] = temp_up_one;
useHistoryRecord(globalStore.done_json);
this.display = false;
break;
case EContextMenuInfoType.MoveDownOneLevel:
if (globalStore.done_json.length === 1 || globalStore.handle_svg_info.index === 0) {
return;
}
const temp_down_one = globalStore.handle_svg_info.info;
globalStore.done_json[globalStore.handle_svg_info.index] =
globalStore.done_json[globalStore.handle_svg_info.index - 1];
globalStore.done_json[globalStore.handle_svg_info.index - 1] = temp_down_one;
useHistoryRecord(globalStore.done_json);
this.display = false;
break;
case EContextMenuInfoType.MoveDownTopLevel:
if (globalStore.done_json.length === 1 || globalStore.handle_svg_info.index === 0) {
return;
}
const temp_up_top = globalStore.handle_svg_info.info;
globalStore.done_json.splice(globalStore.handle_svg_info.index, 1);
globalStore.done_json.unshift(temp_up_top);
useHistoryRecord(globalStore.done_json);
this.display = false;
break;
case EContextMenuInfoType.MoveUpTopLevel:
if (
globalStore.done_json.length === 1 ||
globalStore.handle_svg_info.index === globalStore.done_json.length
) {
return;
}
const temp_down_top = globalStore.handle_svg_info.info;
globalStore.done_json.splice(globalStore.handle_svg_info.index, 1);
globalStore.done_json.push(temp_down_top);
useHistoryRecord(globalStore.done_json);
this.display = false;
break;
default:
break;
}
}
}
});

@ -7,3 +7,22 @@ export interface EditPrivateStoreState {
is_record_history: boolean; is_record_history: boolean;
max_record_times: number; max_record_times: number;
} }
export interface ContextMenuStoreState {
display: boolean;
info: {
[key in EContextMenuInfoType]: IContextMenuInfo;
};
}
export interface IContextMenuInfo {
title: string;
hot_key: string;
enable: boolean;
}
export enum EContextMenuInfoType {
Copy = 'Copy',
Delete = 'Delete',
MoveUpOneLevel = 'MoveUpOneLevel',
MoveDownOneLevel = 'MoveDownOneLevel',
MoveUpTopLevel = 'MoveUpTopLevel',
MoveDownTopLevel = 'MoveDownTopLevel'
}

@ -159,7 +159,6 @@ export const setSvgActualInfo = (done_json: IDoneJson) => {
rectBBox.getAttribute('width') === '0' && rectBBox.getAttribute('width') === '0' &&
rectBBox.getAttribute('height') === '0' rectBBox.getAttribute('height') === '0'
) { ) {
console.log(rectBBox.getAttribute('x'), 168);
rectBBox.setAttribute('x', x.toString()); rectBBox.setAttribute('x', x.toString());
rectBBox.setAttribute('y', y.toString()); rectBBox.setAttribute('y', y.toString());
rectBBox.setAttribute('width', width.toString()); rectBBox.setAttribute('width', width.toString());

Loading…
Cancel
Save