feat: 编辑器添加平移和缩放容器功能
parent
9c7535fb28
commit
a7164e0332
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { Ref } from "vue";
|
||||||
|
import { Container } from "./container";
|
||||||
|
import { Block } from "./block";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
export class Editor {
|
||||||
|
public container: Ref<Container> = {} as Ref<Container>;
|
||||||
|
public content: Ref<Block> = {} as Ref<Block>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,4 +3,4 @@ export * from "./blocker";
|
||||||
export * from "./container";
|
export * from "./container";
|
||||||
export * from "./context";
|
export * from "./context";
|
||||||
export * from "./ref-line";
|
export * from "./ref-line";
|
||||||
|
export * from "./scene";
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { Ref } from "vue";
|
||||||
|
import { Container } from ".";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 场景
|
||||||
|
* @description 处理平移和缩放事件
|
||||||
|
*/
|
||||||
|
export class Scene {
|
||||||
|
private startX = 0;
|
||||||
|
private startY = 0;
|
||||||
|
private cacheX = 0;
|
||||||
|
private cacheY = 0;
|
||||||
|
public minZoom = 0.5;
|
||||||
|
public maxZoom = 10;
|
||||||
|
public zoomStep = 0.1;
|
||||||
|
|
||||||
|
constructor(private container: Ref<Container>) {
|
||||||
|
this.onMouseDown = this.onMouseDown.bind(this);
|
||||||
|
this.onMouseMove = this.onMouseMove.bind(this);
|
||||||
|
this.onMouseUp = this.onMouseUp.bind(this);
|
||||||
|
this.onMouseWheel = this.onMouseWheel.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseDown(e: MouseEvent) {
|
||||||
|
this.startX = e.x;
|
||||||
|
this.startY = e.y;
|
||||||
|
this.cacheX = this.container.value.x;
|
||||||
|
this.cacheY = this.container.value.y;
|
||||||
|
window.addEventListener("mousemove", this.onMouseMove);
|
||||||
|
window.addEventListener("mouseup", this.onMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseMove(e: MouseEvent) {
|
||||||
|
this.container.value.x = this.cacheX + (e.x - this.startX);
|
||||||
|
this.container.value.y = this.cacheY + (e.y - this.startY);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseUp() {
|
||||||
|
window.removeEventListener("mousemove", this.onMouseMove);
|
||||||
|
window.removeEventListener("mouseup", this.onMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseWheel(e: WheelEvent) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const el = e.currentTarget as HTMLElement;
|
||||||
|
const rect = el.getBoundingClientRect();
|
||||||
|
const x = (e.clientX - rect.x) / this.container.value.zoom;
|
||||||
|
const y = (e.clientY - rect.y) / this.container.value.zoom;
|
||||||
|
const delta = -e.deltaY > 0 ? this.zoomStep : -this.zoomStep;
|
||||||
|
|
||||||
|
this.container.value.zoom += delta;
|
||||||
|
if (this.container.value.zoom < this.minZoom) {
|
||||||
|
this.container.value.zoom = this.minZoom;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.container.value.zoom > this.maxZoom) {
|
||||||
|
this.container.value.zoom = this.maxZoom;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.container.value.x += -x * delta + el.offsetWidth * (delta / 2);
|
||||||
|
this.container.value.y += -y * delta + el.offsetHeight * (delta / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<a-modal :visible="true" :fullscreen="true" :footer="false" class="ani-modal">
|
<a-modal :visible="true" :fullscreen="true" :footer="false" class="ani-modal">
|
||||||
<div class="w-full h-full bg-slate-100 grid grid-rows-[auto_1fr]">
|
<div class="w-full h-full bg-slate-100 grid grid-rows-[auto_1fr] select-none">
|
||||||
<div class="h-13 bg-white border-b border-slate-200 z-10">
|
<div class="h-13 bg-white border-b border-slate-200 z-10">
|
||||||
<panel-header></panel-header>
|
<panel-header></panel-header>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -119,8 +119,7 @@ const setContainerOrigin = () => {
|
||||||
const { width, height } = el.getBoundingClientRect();
|
const { width, height } = el.getBoundingClientRect();
|
||||||
const wZoom = width / container.value.width;
|
const wZoom = width / container.value.width;
|
||||||
const hZoom = height / container.value.width;
|
const hZoom = height / container.value.width;
|
||||||
const zoom = Math.floor((wZoom > hZoom ? wZoom : hZoom) * 100) / 100;
|
const zoom = Math.floor((wZoom > hZoom ? wZoom : hZoom) * 10000) / 10000;
|
||||||
// console.log(width, height, wZoom, hZoom, zoom);
|
|
||||||
container.value.zoom = zoom;
|
container.value.zoom = zoom;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,10 @@ const onItemMouseup = () => {
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.resizer {
|
.resizer {
|
||||||
outline: 1px dashed #ccc;
|
outline: 1px dashed #ccc;
|
||||||
|
outline-offset: -1px;
|
||||||
|
&::before {
|
||||||
|
outline-offset: -1px;
|
||||||
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
outline-color: rgb(var(--primary-6));
|
outline-color: rgb(var(--primary-6));
|
||||||
background-color: rgba(var(--primary-1), 0.5);
|
background-color: rgba(var(--primary-1), 0.5);
|
||||||
|
|
@ -117,7 +121,7 @@ const onItemMouseup = () => {
|
||||||
background-color: rgba(var(--primary-1), 0.5);
|
background-color: rgba(var(--primary-1), 0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
::v-deep .vdr-stick {
|
:deep(.vdr-stick) {
|
||||||
border-color: rgb(var(--primary-6));
|
border-color: rgb(var(--primary-6));
|
||||||
}
|
}
|
||||||
:deep(.content-container) {
|
:deep(.content-container) {
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,8 @@
|
||||||
@click="onClick"
|
@click="onClick"
|
||||||
@drop="onDragDrop"
|
@drop="onDragDrop"
|
||||||
@dragover.prevent
|
@dragover.prevent
|
||||||
@wheel="onMouseWheel"
|
@wheel="scene.onMouseWheel"
|
||||||
@mousedown="onMouseDown"
|
@mousedown="scene.onMouseDown"
|
||||||
@mousemove="onMouseMove"
|
|
||||||
>
|
>
|
||||||
<ani-block v-for="block in blocks" :key="block.id" :data="block" :container="container"></ani-block>
|
<ani-block v-for="block in blocks" :key="block.id" :data="block" :container="container"></ani-block>
|
||||||
<template v-if="refLine.active.value">
|
<template v-if="refLine.active.value">
|
||||||
|
|
@ -54,11 +53,12 @@
|
||||||
import { cloneDeep } from "lodash-es";
|
import { cloneDeep } from "lodash-es";
|
||||||
import { CSSProperties } from "vue";
|
import { CSSProperties } from "vue";
|
||||||
import { BlockerMap } from "../blocks";
|
import { BlockerMap } from "../blocks";
|
||||||
import { ContextKey } from "../config";
|
import { ContextKey, Scene } from "../config";
|
||||||
import AniBlock from "./components/block.vue";
|
import AniBlock from "./components/block.vue";
|
||||||
import AniHeader from "./components/header.vue";
|
import AniHeader from "./components/header.vue";
|
||||||
|
|
||||||
const { blocks, container, refLine, setCurrentBlock } = inject(ContextKey)!;
|
const { blocks, container, refLine, setCurrentBlock } = inject(ContextKey)!;
|
||||||
|
const scene = new Scene(container);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清空当前组件
|
* 清空当前组件
|
||||||
|
|
@ -69,52 +69,6 @@ const onClick = (e: Event) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isStart = ref(false);
|
|
||||||
const position = ref({
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
startX: 0,
|
|
||||||
startY: 0,
|
|
||||||
mouseX: 0,
|
|
||||||
mouseY: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 拖拽容器:开始
|
|
||||||
*/
|
|
||||||
const onMouseDown = (e: MouseEvent) => {
|
|
||||||
isStart.value = true;
|
|
||||||
position.value.startX = e.offsetX;
|
|
||||||
position.value.startY = e.offsetY;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 拖拽容器:移动
|
|
||||||
*/
|
|
||||||
const onMouseMove = (e: MouseEvent) => {
|
|
||||||
if (!isStart.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const scale = container.value.zoom;
|
|
||||||
container.value.x += (e.offsetX - position.value.startX) * scale;
|
|
||||||
container.value.y += (e.offsetY - position.value.startY) * scale;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 拖拽容器:结束
|
|
||||||
*/
|
|
||||||
const onMouseUp = () => {
|
|
||||||
isStart.value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
window.addEventListener("mouseup", onMouseUp);
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
window.removeEventListener("mouseup", onMouseUp);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 容器样式
|
* 容器样式
|
||||||
*/
|
*/
|
||||||
|
|
@ -128,8 +82,6 @@ const containerStyle = computed(() => {
|
||||||
backgroundImage: bgImage ? `url(${bgImage})` : undefined,
|
backgroundImage: bgImage ? `url(${bgImage})` : undefined,
|
||||||
backgroundSize: "100% 100%",
|
backgroundSize: "100% 100%",
|
||||||
transform: `translate3d(${x}px, ${y}px, 0) scale(${zoom})`,
|
transform: `translate3d(${x}px, ${y}px, 0) scale(${zoom})`,
|
||||||
// transform: `matrix(${zoom}, 0, 0, ${zoom}, ${x}, ${y})`,
|
|
||||||
// transformOrigin: "0 0",
|
|
||||||
} as CSSProperties;
|
} as CSSProperties;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -157,35 +109,6 @@ const onDragDrop = (e: DragEvent) => {
|
||||||
y: e.offsetY,
|
y: e.offsetY,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 滚轮缩放容器
|
|
||||||
*/
|
|
||||||
const onMouseWheel = (e: WheelEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const prezoom = container.value.zoom;
|
|
||||||
let zoom = prezoom;
|
|
||||||
if (e.deltaY > 0) {
|
|
||||||
zoom += 0.1;
|
|
||||||
if (zoom > 10) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
zoom -= 0.1;
|
|
||||||
if (zoom < 0.1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
zoom = parseFloat(zoom.toFixed(1));
|
|
||||||
// const { x, y } = position.value
|
|
||||||
// const x1 = x + e.offsetX;
|
|
||||||
// const y1 = y + e.offsetY;
|
|
||||||
// position.value.x = x1 - (x1 - x) * (zoom / prezoom);
|
|
||||||
// position.value.y = y1 - (y1 - y) * (zoom / prezoom);
|
|
||||||
// position.value.x = e.clientX;
|
|
||||||
// position.value.y = e.clientY;
|
|
||||||
container.value.zoom = zoom;
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue