LinYeFangHuo/src/views/chart/ContentEdit/components/EditRule/index.vue

370 lines
9.3 KiB
Vue

<template>
<div class="go-sketch-rule">
<sketch-rule
v-if="sketchRuleReDraw"
:thick="thick"
:scale="scale"
:width="canvasBox().width"
:height="canvasBox().height"
:startX="startX"
:startY="startY"
:lines="lines"
:palette="paletteStyle"
>
</sketch-rule>
<div ref="$app" class="edit-screens" @scroll="handleScroll">
<div ref="$container" class="edit-screen-container" :style="{ width: containerWidth }">
<div
ref="refSketchRuleBox"
class="canvas"
@mousedown="dragCanvas"
:style="{ marginLeft: '-' + (canvasBox().width / 2 - 25) + 'px' }"
>
<div :style="{ pointerEvents: isPressSpace ? 'none' : 'auto' }">
<slot></slot>
</div>
</div>
</div>
</div>
<!-- 修复右下角白点用的 -->
<!-- <div v-if="designStore.getDarkTheme" class="fix-edit-screens-block"></div> -->
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, toRefs, watch, onUnmounted, computed } from 'vue';
import { listen } from 'dom-helpers';
import { useDesignStore } from '@/store/modules/designStore/designStore';
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore';
import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore';
import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d';
import throttle from 'lodash/throttle';
const chartEditStore = useChartEditStore();
const chartLayoutStore = useChartLayoutStore();
const designStore = useDesignStore();
const thick = 20;
let prevMoveXValue = [0, 0];
let prevMoveYValue = [0, 0];
const $app = ref();
const sketchRuleReDraw = ref(true);
const refSketchRuleBox = ref();
const $container = ref();
const isPressSpace = ref(false);
const cursorStyle = ref('auto');
const { width, height } = toRefs(chartEditStore.getEditCanvasConfig);
const startX = ref(0);
const startY = ref(0);
const lines = reactive({ h: [], v: [] });
const scale = computed(() => {
return chartEditStore.getEditCanvas.scale;
});
// 滚动条拖动的宽度
const containerWidth = computed(() => {
return `${window.innerWidth * 2}px`;
});
// 滚动条拖动的高度
const containerHeight = computed(() => {
return `${height.value * 2}px`;
});
// 主题
const paletteStyle = computed(() => {
const isDarkTheme = designStore.getDarkTheme;
return isDarkTheme
? {
bgColor: '#18181c',
longfgColor: '#4d4d4d',
shortfgColor: '#4d4d4d',
fontColor: '#4d4d4d',
shadowColor: '#18181c',
borderColor: '#18181c',
cornerActiveColor: '#18181c',
}
: {};
});
// 颜色
const themeColor = computed(() => {
return designStore.getAppTheme;
});
// 处理鼠标拖动
const handleWheel = (e: any) => {
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
let resScale = scale.value;
// 放大(200%)
if (e.wheelDelta >= 0 && scale.value < 2) {
resScale = scale.value + 0.05;
chartEditStore.setScale(resScale);
return;
}
// 缩小(10%)
if (e.wheelDelta < 0 && scale.value > 0.1) {
resScale = scale.value - 0.05;
chartEditStore.setScale(resScale);
}
}
};
// 滚动条处理
const handleScroll = () => {
if (!$app.value) return;
const screensRect = $app.value.getBoundingClientRect();
const canvasRect = refSketchRuleBox.value.getBoundingClientRect();
// 标尺开始的刻度
startX.value = (screensRect.left + thick - canvasRect.left) / scale.value;
startY.value = (screensRect.top + thick - canvasRect.top) / scale.value;
};
// 拖拽处理
const dragCanvas = (e: any) => {
e.preventDefault();
e.stopPropagation();
if (e.which == 2) isPressSpace.value = true;
else if (!window.$KeyboardActive?.space) return;
// @ts-ignore
document.activeElement?.blur();
const startX = e.pageX;
const startY = e.pageY;
const listenMousemove = listen(window, 'mousemove', (e: any) => {
const nx = e.pageX - startX;
const ny = e.pageY - startY;
const [prevMoveX1, prevMoveX2] = prevMoveXValue;
const [prevMoveY1, prevMoveY2] = prevMoveYValue;
prevMoveXValue = [prevMoveX2, nx];
prevMoveYValue = [prevMoveY2, ny];
$app.value.scrollLeft -=
prevMoveX2 > prevMoveX1
? Math.abs(prevMoveX2 - prevMoveX1)
: -Math.abs(prevMoveX2 - prevMoveX1);
$app.value.scrollTop -=
prevMoveY2 > prevMoveY1
? Math.abs(prevMoveY2 - prevMoveY1)
: -Math.abs(prevMoveY2 - prevMoveY1);
});
const listenMouseup = listen(window, 'mouseup', () => {
listenMousemove();
listenMouseup();
prevMoveXValue = [0, 0];
prevMoveYValue = [0, 0];
isPressSpace.value = false;
});
};
// 计算画布大小
const canvasBox = () => {
const layoutDom = document.getElementById('go-chart-edit-layout');
if (layoutDom) {
// 此处减去滚动条的宽度和高度
const scrollW = 20;
return {
height: layoutDom.clientHeight - scrollW,
width: layoutDom.clientWidth - scrollW,
};
}
return {
width: width.value,
height: height.value,
};
};
// 重绘标尺
const reDraw = throttle(() => {
sketchRuleReDraw.value = false;
setTimeout(() => {
sketchRuleReDraw.value = true;
}, 10);
}, 20);
// 滚动居中
const canvasPosCenter = () => {
const { width: containerWidth, height: containerHeight } =
$container.value.getBoundingClientRect();
const { width, height } = canvasBox();
$app.value.scrollLeft = containerWidth / 2 - width / 2;
$app.value.scrollTop = containerHeight / 2 - height / 2;
};
// 处理主题变化
watch(
() => designStore.getDarkTheme,
() => {
reDraw();
},
);
// // 处理标尺重制大小
watch(
() => scale.value,
(newValue, oldValue) => {
if (oldValue !== newValue && chartLayoutStore.getRePositionCanvas) {
chartLayoutStore.setItemUnHandle(ChartLayoutStoreEnum.RE_POSITION_CANVAS, false);
}
handleScroll();
setTimeout(() => {
canvasPosCenter();
reDraw();
}, 400);
},
);
// 处理鼠标样式
watch(
() => isPressSpace.value,
(newValue) => {
cursorStyle.value = newValue ? 'grab' : 'auto';
},
);
onMounted(() => {
if ($app.value) {
$app.value.addEventListener('wheel', handleWheel, { passive: false });
canvasPosCenter();
}
});
onUnmounted(() => {
if ($app.value) {
$app.value.removeEventListener('wheel', handleWheel);
}
});
window.onKeySpacePressHold = (isHold: boolean) => {
isPressSpace.value = isHold;
};
</script>
<style>
/* 使用 SCSS 会报错,直接使用最基础的 CSS 进行修改,
此库有计划 Vue3 版本,但是开发的时候还没发布 */
#mb-ruler {
top: 0;
left: 0;
}
/* 横线 */
#mb-ruler .v-container .lines .line {
/* 最大缩放 200% */
width: 200vw !important;
border-top: 1px dashed v-bind('themeColor') !important;
}
#mb-ruler .v-container .indicator {
border-bottom: 1px dashed v-bind('themeColor') !important;
}
/* 竖线 */
#mb-ruler .h-container .lines .line {
/* 最大缩放 200% */
height: 200vh !important;
border-left: 1px dashed v-bind('themeColor') !important;
}
#mb-ruler .h-container .indicator {
border-left: 1px dashed v-bind('themeColor') !important;
}
/* 坐标数值背景颜色 */
#mb-ruler .indicator .value {
background-color: rgba(0, 0, 0, 0);
}
/* 删除按钮 */
#mb-ruler .line .del {
padding: 0;
color: v-bind('themeColor');
font-size: 26px;
font-weight: bolder;
}
#mb-ruler .corner {
border-width: 0 !important;
}
</style>
<style lang="scss" scoped>
@include go('sketch-rule') {
overflow: hidden;
width: 100%;
height: 100%;
.edit-screens {
position: absolute;
width: 100%;
height: 90%;
overflow: auto;
user-select: none;
padding-bottom: 0px;
/* firefox */
scrollbar-color: rgba(144, 146, 152, 0.3) transparent;
scrollbar-width: thin;
/* chrome */
&::-webkit-scrollbar,
&::-webkit-scrollbar-track-piece {
background-color: transparent;
}
&::-webkit-scrollbar {
width: 7px;
}
&::-webkit-scrollbar-thumb {
border-radius: 5px;
background-color: rgba(144, 146, 152, 0.3);
}
// 修复右下角白点用的
&::-webkit-scrollbar-corner {
background-color: transparent;
}
}
.fix-edit-screens-block {
position: absolute;
bottom: 0;
right: 0;
width: 10px;
height: 10px;
background-color: $--color-dark-bg-1;
}
.edit-screen-container {
position: absolute;
height: v-bind('containerHeight');
top: 0;
left: 0;
}
.canvas {
position: absolute;
top: 50%;
left: 50%;
transform-origin: 50% 0;
transform: translateY(-50%);
&:hover {
cursor: v-bind('cursorStyle');
}
&:active {
cursor: crosshair;
}
}
}
</style>