feat: 编辑器添加平移和缩放容器功能

master
luoer 2023-10-23 17:23:22 +08:00
parent 9c7535fb28
commit a7164e0332
6 changed files with 92 additions and 86 deletions

View File

@ -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
}
}

View File

@ -3,4 +3,4 @@ export * from "./blocker";
export * from "./container";
export * from "./context";
export * from "./ref-line";
export * from "./scene";

View File

@ -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);
}
}

View File

@ -1,6 +1,6 @@
<template>
<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">
<panel-header></panel-header>
</div>
@ -119,8 +119,7 @@ const setContainerOrigin = () => {
const { width, height } = el.getBoundingClientRect();
const wZoom = width / container.value.width;
const hZoom = height / container.value.width;
const zoom = Math.floor((wZoom > hZoom ? wZoom : hZoom) * 100) / 100;
// console.log(width, height, wZoom, hZoom, zoom);
const zoom = Math.floor((wZoom > hZoom ? wZoom : hZoom) * 10000) / 10000;
container.value.zoom = zoom;
}
};

View File

@ -106,6 +106,10 @@ const onItemMouseup = () => {
<style lang="less" scoped>
.resizer {
outline: 1px dashed #ccc;
outline-offset: -1px;
&::before {
outline-offset: -1px;
}
&:hover {
outline-color: rgb(var(--primary-6));
background-color: rgba(var(--primary-1), 0.5);
@ -117,7 +121,7 @@ const onItemMouseup = () => {
background-color: rgba(var(--primary-1), 0.5);
}
}
::v-deep .vdr-stick {
:deep(.vdr-stick) {
border-color: rgb(var(--primary-6));
}
:deep(.content-container) {

View File

@ -13,9 +13,8 @@
@click="onClick"
@drop="onDragDrop"
@dragover.prevent
@wheel="onMouseWheel"
@mousedown="onMouseDown"
@mousemove="onMouseMove"
@wheel="scene.onMouseWheel"
@mousedown="scene.onMouseDown"
>
<ani-block v-for="block in blocks" :key="block.id" :data="block" :container="container"></ani-block>
<template v-if="refLine.active.value">
@ -54,11 +53,12 @@
import { cloneDeep } from "lodash-es";
import { CSSProperties } from "vue";
import { BlockerMap } from "../blocks";
import { ContextKey } from "../config";
import { ContextKey, Scene } from "../config";
import AniBlock from "./components/block.vue";
import AniHeader from "./components/header.vue";
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,
backgroundSize: "100% 100%",
transform: `translate3d(${x}px, ${y}px, 0) scale(${zoom})`,
// transform: `matrix(${zoom}, 0, 0, ${zoom}, ${x}, ${y})`,
// transformOrigin: "0 0",
} as CSSProperties;
});
@ -157,35 +109,6 @@ const onDragDrop = (e: DragEvent) => {
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>
<style scoped>