293 lines
8.6 KiB
Vue
293 lines
8.6 KiB
Vue
<template>
|
|
<div class="magnifier" v-show="isShow">
|
|
<div
|
|
v-if="isZoomed"
|
|
class="magnifier-glass"
|
|
:style="{
|
|
left: zoomedPosition.x + 'px',
|
|
top: zoomedPosition.y + 'px',
|
|
transform: `translate(-50%, -50%) scale(1)`,
|
|
width: '300px',
|
|
height: '200px',
|
|
backgroundColor: 'white'
|
|
}"
|
|
>
|
|
<canvas ref="magnifierCanvas" width="300" height="200"></canvas>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, reactive } from 'vue'
|
|
|
|
const isShow = ref(true)
|
|
const isZoomed = ref(false)
|
|
const magnifierCanvas = ref(null)
|
|
const zoomLevel = 1.8
|
|
|
|
const zoomedPosition = reactive({
|
|
x: 0,
|
|
y: 0
|
|
})
|
|
|
|
// 绘制放大区域
|
|
function drawMagnifiedArea(x, y, container) {
|
|
if (!magnifierCanvas.value) return
|
|
|
|
const ctx = magnifierCanvas.value.getContext('2d', { willReadFrequently: true })
|
|
const container1 = document.querySelector('#canvas-container')
|
|
const container2 = document.querySelector('#canvas-container1')
|
|
const rect1 = container1.getBoundingClientRect()
|
|
const rect2 = container2.getBoundingClientRect()
|
|
|
|
// 计算过渡区域
|
|
const transitionZone = 20 // 过渡区域宽度(像素)
|
|
const isInTransition = Math.abs(x - rect2.left) < transitionZone
|
|
|
|
ctx.clearRect(0, 0, 300, 200)
|
|
ctx.imageSmoothingEnabled = true
|
|
ctx.imageSmoothingQuality = 'high'
|
|
|
|
if (false) {
|
|
if (isInTransition) {
|
|
// 在过渡区域,混合两个容器的内容
|
|
const weight2 = (x - (rect2.left - transitionZone)) / (transitionZone * 2)
|
|
const weight1 = 1 - weight2
|
|
|
|
// 绘制第一个容器的内容
|
|
drawContainerContent(ctx, container1, x, y, rect1, weight1)
|
|
// 绘制第二个容器的内容
|
|
drawContainerContent(ctx, container2, x, y, rect2, weight2)
|
|
} else {
|
|
// 在非过渡区域,只绘制当前容器的内容
|
|
const currentContainer = x < rect2.left ? container1 : container2
|
|
const currentRect = x < rect2.left ? rect1 : rect2
|
|
drawContainerContent(ctx, currentContainer, x, y, currentRect, 1)
|
|
}
|
|
} else {
|
|
drawContainerContent(ctx, container1, x, y, rect1, 1)
|
|
drawContainerContent(ctx, container2, x, y, rect2, 1)
|
|
}
|
|
}
|
|
|
|
// 新增:绘制单个容器内容的辅助函数
|
|
function drawContainerContent_old(ctx, container, x, y, rect, alpha) {
|
|
if (alpha === 0) return
|
|
|
|
ctx.globalAlpha = alpha
|
|
const layers = [
|
|
container.querySelector('#bottomCanvas, #bottomCanvas1'),
|
|
container.querySelector('#leftCanvas, #rightCanvas'),
|
|
container.querySelector('#topCanvas, #topCanvas1')
|
|
].filter((canvas) => canvas)
|
|
|
|
layers.forEach((canvas) => {
|
|
const canvasRect = canvas.getBoundingClientRect()
|
|
const canvasX = x - canvasRect.left
|
|
const canvasY = y - canvasRect.top
|
|
|
|
ctx.drawImage(canvas, canvasX - 75, canvasY - 50, 150, 100, 0, 0, 300, 200)
|
|
})
|
|
ctx.globalAlpha = 1
|
|
}
|
|
|
|
function drawContainerContent(ctx, container, x, y, rect, alpha) {
|
|
if (alpha === 0) return
|
|
|
|
ctx.globalAlpha = alpha
|
|
const layers = [
|
|
container.querySelector('#bottomCanvas, #bottomCanvas1'),
|
|
container.querySelector('#leftCanvas, #rightCanvas'),
|
|
container.querySelector('#topCanvas, #topCanvas1')
|
|
].filter((canvas) => canvas)
|
|
|
|
layers.forEach((canvas) => {
|
|
const canvasRect = canvas.getBoundingClientRect()
|
|
const canvasX = x - canvasRect.left
|
|
const canvasY = y - canvasRect.top
|
|
const canvasY_max = y + 50 >= rect.bottom ? rect.bottom : y + 50
|
|
|
|
if (['topCanvas', 'topCanvas1'].includes(canvas.id)) {
|
|
const leftCanvas = container.querySelector('#leftCanvas, #rightCanvas')
|
|
if (canvasRect.right > leftCanvas.getBoundingClientRect().right) {
|
|
let borderLeft =
|
|
x - leftCanvas.getBoundingClientRect().right > 75
|
|
? x - 75
|
|
: leftCanvas.getBoundingClientRect().right
|
|
let borderLeft_span =
|
|
x <= leftCanvas.getBoundingClientRect().right
|
|
? 75 + leftCanvas.getBoundingClientRect().right - x
|
|
: x - leftCanvas.getBoundingClientRect().right >= 75
|
|
? 0
|
|
: 75 - x + leftCanvas.getBoundingClientRect().right
|
|
let canvasRectRight_effective =
|
|
rect.right > canvasRect.right ? canvasRect.right : rect.right
|
|
if (
|
|
borderLeft_span < 150 &&
|
|
borderLeft >= leftCanvas.getBoundingClientRect().right &&
|
|
borderLeft <= canvasRectRight_effective
|
|
) {
|
|
let borderRight =
|
|
borderLeft_span > 75
|
|
? leftCanvas.getBoundingClientRect().right + 150 - borderLeft_span
|
|
: x + 75
|
|
if (borderRight >= canvasRectRight_effective) borderRight = canvasRectRight_effective
|
|
let swidth = borderRight - borderLeft
|
|
ctx.drawImage(
|
|
canvas,
|
|
borderLeft - canvasRect.left,
|
|
canvasY - 50,
|
|
swidth,
|
|
canvasY_max - (y - 50),
|
|
borderLeft_span * 2,
|
|
0,
|
|
swidth * 2,
|
|
(canvasY_max - (y - 50)) * 2
|
|
)
|
|
}
|
|
}
|
|
} else if (['bottomCanvas', 'bottomCanvas1'].includes(canvas.id)) {
|
|
const leftCanvas = container.querySelector('#leftCanvas, #rightCanvas')
|
|
let canvasRectRight_effective = rect.right > canvasRect.right ? canvasRect.right : rect.right
|
|
if (x + 75 > leftCanvas.getBoundingClientRect().right && x - 75 < canvasRectRight_effective) {
|
|
let swidth = x + 75 <= canvasRectRight_effective ? 150 : 75 + canvasRectRight_effective - x
|
|
ctx.drawImage(
|
|
canvas,
|
|
canvasX - 75,
|
|
canvasY - 50,
|
|
swidth,
|
|
canvasY_max - (y - 50),
|
|
0,
|
|
0,
|
|
swidth * 2,
|
|
(canvasY_max - (y - 50)) * 2
|
|
)
|
|
}
|
|
} else {
|
|
ctx.drawImage(
|
|
canvas,
|
|
canvasX - 75,
|
|
canvasY - 50,
|
|
150,
|
|
canvasY_max - (y - 50),
|
|
0,
|
|
0,
|
|
300,
|
|
(canvasY_max - (y - 50)) * 2
|
|
)
|
|
}
|
|
})
|
|
ctx.globalAlpha = 1
|
|
}
|
|
|
|
// 处理鼠标移动
|
|
function handleMouseMove(e) {
|
|
if (!isZoomed.value) return
|
|
|
|
const container1 = document.querySelector('#canvas-container')
|
|
const container2 = document.querySelector('#canvas-container1')
|
|
|
|
const rect1 = container1.getBoundingClientRect()
|
|
const rect2 = container2.getBoundingClientRect()
|
|
|
|
// 检查鼠标是否在任一容器内
|
|
const isInContainer1 =
|
|
e.clientX >= rect1.left &&
|
|
e.clientX <= rect1.right &&
|
|
e.clientY >= rect1.top &&
|
|
e.clientY <= rect1.bottom
|
|
const isInContainer2 =
|
|
e.clientX >= rect2.left &&
|
|
e.clientX <= rect2.right &&
|
|
e.clientY >= rect2.top &&
|
|
e.clientY <= rect2.bottom
|
|
|
|
if (!isInContainer1 && !isInContainer2) {
|
|
isZoomed.value = false
|
|
document.removeEventListener('mousemove', handleMouseMove)
|
|
return
|
|
}
|
|
|
|
zoomedPosition.x = e.clientX
|
|
zoomedPosition.y = e.clientY
|
|
|
|
// 简单判断使用哪个容器,不再考虑过渡区域
|
|
const currentContainer = e.clientX < rect2.left ? container1 : container2
|
|
drawMagnifiedArea(e.clientX, e.clientY, currentContainer)
|
|
}
|
|
|
|
// 处理鼠标点击
|
|
function handleMouseDown(e) {
|
|
const container = e.target.closest('#canvas-container, #canvas-container1')
|
|
if (!container || e.button !== 0) return
|
|
|
|
const rect = container.getBoundingClientRect()
|
|
const isInContainer =
|
|
e.clientX >= rect.left &&
|
|
e.clientX <= rect.right &&
|
|
e.clientY >= rect.top &&
|
|
e.clientY <= rect.bottom
|
|
|
|
if (!isInContainer) return
|
|
|
|
if (isZoomed.value) {
|
|
isZoomed.value = false
|
|
document.removeEventListener('mousemove', handleMouseMove)
|
|
} else {
|
|
isZoomed.value = true
|
|
nextTick(() => {
|
|
zoomedPosition.x = e.clientX
|
|
zoomedPosition.y = e.clientY
|
|
drawMagnifiedArea(e.clientX, e.clientY, container)
|
|
document.addEventListener('mousemove', handleMouseMove)
|
|
})
|
|
}
|
|
}
|
|
|
|
const infoParams = defineProps({
|
|
Isfd: Boolean
|
|
})
|
|
|
|
watch([() => infoParams.Isfd], ([newfd], [oldds]) => {
|
|
if (newfd !== oldds) {
|
|
if (newfd) {
|
|
document.addEventListener('mousedown', handleMouseDown)
|
|
} else {
|
|
document.removeEventListener('mousedown', handleMouseDown)
|
|
document.removeEventListener('mousemove', handleMouseMove)
|
|
isZoomed.value = false
|
|
}
|
|
}
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
document.removeEventListener('mousedown', handleMouseDown)
|
|
document.removeEventListener('mousemove', handleMouseMove)
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.magnifier {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
pointer-events: none;
|
|
z-index: 9999;
|
|
}
|
|
|
|
.magnifier-glass {
|
|
position: fixed;
|
|
border: 1px solid rgba(255, 0, 0, 0.5);
|
|
pointer-events: none;
|
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
|
overflow: hidden;
|
|
}
|
|
|
|
canvas {
|
|
transform: scale(1.8);
|
|
transform-origin: center center;
|
|
}
|
|
</style>
|