Commit 4e21d926 authored by jiaxu.yan's avatar jiaxu.yan

新增组态展示

parent 1832971f
# just a flag
ENV = 'development'
port= 8080
# base api
VUE_APP_BASE_API = '/dev-api'
VUE_CLI_BABEL_TRANSPILE_MODULES = true
......
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas点位与交互效果</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
font-family: Arial, sans-serif;
}
.container {
text-align: center;
}
canvas {
background-color: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
cursor: crosshair;
}
.controls {
margin-top: 20px;
}
button {
padding: 8px 16px;
margin: 0 5px;
cursor: pointer;
}
.mode-indicator {
margin-top: 10px;
font-weight: bold;
color: #333;
}
</style>
</head>
<body>
<div class="container">
<h1>Canvas点位交互演示</h1>
<canvas id="myCanvas" width="600" height="400"></canvas>
<div class="controls">
<button id="addPoint">添加随机点位</button>
<button id="clearAll">清除所有点位</button>
<button id="toggleMode">切换模式: 点击选择</button>
<p id="info">当前模式: 点击选择点位</p>
<p class="mode-indicator" id="modeInfo">在拖拽创建模式下,按住鼠标拖动可以创建点位</p>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const addPointBtn = document.getElementById('addPoint');
const clearAllBtn = document.getElementById('clearAll');
const toggleModeBtn = document.getElementById('toggleMode');
const infoText = document.getElementById('info');
const modeInfoText = document.getElementById('modeInfo');
// 存储所有点位的数组
let points = [];
let isDragCreationMode = false;
let isDragging = false;
let dragStartX, dragStartY;
let currentDragPoint = null;
// 点位类
class Point {
constructor(x, y, radius = 10) {
this.x = x;
this.y = y;
this.radius = radius;
this.originalRadius = radius;
this.color = this.getRandomColor();
this.isActive = false;
}
getRandomColor() {
// const r = Math.floor(Math.random() * 200 + 55);
// const g = Math.floor(Math.random() * 200 + 55);
// const b = Math.floor(Math.random() * 200 + 55);
return `rgb(0, 0 ,0)`;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.isActive ? '#ff0000' : this.color;
ctx.fill();
ctx.strokeStyle = '#333';
ctx.stroke();
// 如果是激活状态,添加脉冲动画效果
if (this.isActive) {
this.radius = this.originalRadius * (1 + Math.sin(Date.now() / 200) * 0.2);
} else {
this.radius = this.originalRadius;
}
}
contains(x, y) {
const distance = Math.sqrt((x - this.x) ** 2 + (y - this.y) ** 2);
return distance <= this.radius;
}
}
// 添加随机点位
function addRandomPoint() {
const radius = Math.floor(Math.random() * 15 + 5);
const x = Math.random() * (canvas.width - radius * 2) + radius;
const y = Math.random() * (canvas.height - radius * 2) + radius;
const point = new Point(x, y, radius);
points.push(point);
drawAllPoints();
}
// 在指定位置添加点位
function addPointAt(x, y, radius = 10) {
const point = new Point(x, y, radius);
points.push(point);
return point;
}
// 清除所有点位
function clearAllPoints() {
points = [];
ctx.clearRect(0, 0, canvas.width, canvas.height);
infoText.textContent = "已清除所有点位";
}
// 绘制所有点位
function drawAllPoints() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制所有已存在的点位
points.forEach(point => point.draw());
// 如果在拖拽创建模式下正在拖动,绘制临时点位
if (isDragCreationMode && isDragging && currentDragPoint) {
currentDragPoint.draw();
// 绘制拖拽引导线
ctx.beginPath();
ctx.moveTo(dragStartX, dragStartY);
ctx.lineTo(currentDragPoint.x, currentDragPoint.y);
ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)';
ctx.setLineDash([5, 3]);
ctx.stroke();
ctx.setLineDash([]);
}
requestAnimationFrame(drawAllPoints);
}
// 切换模式
function toggleMode() {
isDragCreationMode = !isDragCreationMode;
// 更新UI
if (isDragCreationMode) {
toggleModeBtn.textContent = "切换模式: 拖拽创建";
infoText.textContent = "当前模式: 拖拽创建点位";
modeInfoText.style.display = 'block';
canvas.style.cursor = 'crosshair';
} else {
toggleModeBtn.textContent = "切换模式: 点击选择";
infoText.textContent = "当前模式: 点击选择点位";
modeInfoText.style.display = 'none';
canvas.style.cursor = 'default';
}
// 取消任何进行中的拖拽
isDragging = false;
currentDragPoint = null;
}
// 检查点击是否在点位上
function handleClick(x, y) {
if (isDragCreationMode) return;
let clickedPoint = null;
// 先取消所有点位的激活状态
points.forEach(point => {
point.isActive = false;
});
// 检查点击是否在某个点位上
for (let i = points.length - 1; i >= 0; i--) {
if (points[i].contains(x, y)) {
clickedPoint = points[i];
clickedPoint.isActive = true;
infoText.textContent = `点击了点位 (${Math.round(clickedPoint.x)}, ${Math.round(clickedPoint.y)})`;
break;
}
}
if (!clickedPoint) {
infoText.textContent = "点击空白区域";
}
}
// 事件监听
addPointBtn.addEventListener('click', addRandomPoint);
clearAllBtn.addEventListener('click', clearAllPoints);
toggleModeBtn.addEventListener('click', toggleMode);
canvas.addEventListener('click', function(e) {
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
handleClick(x, y);
});
// 拖拽创建点位相关事件
canvas.addEventListener('mousedown', function(e) {
if (!isDragCreationMode) return;
const rect = canvas.getBoundingClientRect();
dragStartX = e.clientX - rect.left;
dragStartY = e.clientY - rect.top;
// 检查是否点击了现有点位
let clickedExisting = false;
for (let i = points.length - 1; i >= 0; i--) {
if (points[i].contains(dragStartX, dragStartY)) {
clickedExisting = true;
break;
}
}
if (!clickedExisting) {
isDragging = true;
currentDragPoint = addPointAt(dragStartX, dragStartY, 5);
infoText.textContent = "拖动鼠标调整点位大小";
}
});
canvas.addEventListener('mousemove', function(e) {
if (!isDragCreationMode || !isDragging || !currentDragPoint) return;
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// 计算拖拽距离作为半径
const distance = Math.sqrt(Math.pow(x - dragStartX, 2) + Math.pow(y - dragStartY, 2));
currentDragPoint.originalRadius = Math.min(Math.max(distance, 5), 50); // 限制半径范围
currentDragPoint.x = dragStartX;
currentDragPoint.y = dragStartY;
});
canvas.addEventListener('mouseup', function(e) {
if (!isDragCreationMode || !isDragging) return;
isDragging = false;
infoText.textContent = `已创建点位 (${Math.round(currentDragPoint.x)}, ${Math.round(currentDragPoint.y)}), 半径: ${Math.round(currentDragPoint.originalRadius)}`;
currentDragPoint = null;
});
canvas.addEventListener('mouseleave', function() {
if (isDragging) {
// 如果鼠标离开画布时正在拖拽,取消当前拖拽
if (currentDragPoint) {
points.pop(); // 移除未完成的点位
}
isDragging = false;
currentDragPoint = null;
}
});
// 初始绘制
drawAllPoints();
modeInfoText.style.display = 'none';
// 添加几个初始点位
// for (let i = 0; i < 5; i++) {
// addRandomPoint();
// }
});
</script>
</body>
</html>
<template>
<div>
<div class="pageindex">
<div class="index-top">
<div class="top-left"></div>
<div class="top-right">状态</div>
</div>
<div class="index-bottom">
冷却器状态
</div>
</div>
<div class="left-bar">
<el-button :type="type == 1" @click="getType(1)">第一视角</el-button>
<el-button :type="type == 2" @click="getType(2)">第二视角</el-button>
<el-button :type="type == 3" @click="getType(3)">第三视角</el-button>
<el-button :type="type == 4" @click="getType(4)">第四视角</el-button>
<el-button :type="type == 5" @click="getType(5)">第五视角</el-button>
<el-button :type="type == 6" @click="getType(6)">第六视角</el-button>
</div>
<pie> </pie>
</div>
</template>
<script>
import pie from '@/views/makePie/index.vue'
export default {
components: {
pie: pie
},
data() {
return {
name: '特变电压器'
name: '特变电压器',
type: 1
}
},
getType(e) {
console.log(e)
this.type = e
}
}
</script>
<style lang="scss" scoped>
.pageindex{
.pageindex {
width: 100%;
height: 100%;
.index-top{
.index-top {
display: flex;
.top-left{
.top-left {
display: flex;
width: 40%;
align-items:center;
align-items: center;
justify-content: center;
height: 400px;
border: 1px solid #EEE;
border: 1px solid #eee;
}
.top-right{
.top-right {
display: flex;
width: 60%;
align-items:center;
align-items: center;
justify-content: center;
height: 400px;
border: 1px solid #EEE;
border: 1px solid #eee;
}
}
.index-bottom{
.index-bottom {
display: flex;
align-items:center;
align-items: center;
justify-content: center;
height: 300px;
border: 1px solid #EEE;
height: 300px;
border: 1px solid #eee;
}
}
</style>
<template>
<div class="container">
<canvas
ref="canvas"
:width="width"
:height="height"
@click="handleClick"
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@mouseleave="handleMouseLeave"
></canvas>
<div class="left-bar">
<el-button @click="getType(1)">第一视角</el-button>
<el-button @click="getType(2)">第二视角</el-button>
<el-button @click="getType(3)">第三视角</el-button>
<el-button @click="getType(4)">第四视角</el-button>
<el-button @click="getType(5)">第五视角</el-button>
<el-button @click="getType(6)">第六视角</el-button>
</div>
<div class="right-bar">
<el-upload
ref="upload"
:action="upload_url"
:before-upload="beforeUpload"
:show-file-list="false"
:auto-upload="true"
:headers="headers"
accept="image/*"
:on-success="handleSuccess"
>
<el-button slot="trigger">上传文件</el-button>
</el-upload>
</div>
<div class="controls">
<el-button @click="clearAllPoints">清除所有点位</el-button>
<el-button @click="toggleMode">
切换模式: {{ isDragCreationMode ? '点击选择' : '拖拽创建' }}
</el-button>
<p id="info">
当前模式: {{ isDragCreationMode ? '拖拽创建点位' : '点击选择点位' }}
</p>
<p v-if="isDragCreationMode" class="mode-indicator">
在拖拽创建模式下,按住鼠标拖动可以创建点位
</p>
</div>
</div>
</template>
<script>
import { getToken } from '@/utils/auth'
export default {
name: 'PointCanvas',
props: {
width: {
type: Number,
default: 600
},
height: {
type: Number,
default: 400
},
initialPoints: {
type: Array,
default: () => []
}
},
data() {
return {
// 设置上传的请求头部
headers: { Authorization: 'Bearer ' + getToken() },
// 上传的地址
upload_url: process.env.VUE_APP_BASE_API + '/system/user/importExcel',
ctx: null,
points: [],
isDragCreationMode: false,
isDragging: false,
dragStartX: 0,
dragStartY: 0,
currentDragPoint: null,
animationFrameId: null,
infoText: '点击画布上的点位会有交互效果'
}
},
mounted() {
this.initCanvas()
this.drawAllPoints()
// 添加初始点位
if (this.initialPoints.length > 0) {
this.points = this.initialPoints.map(p => new Point(p.x, p.y, p.radius))
} else {
for (let i = 0; i < 5; i++) {
this.addRandomPoint()
}
}
},
beforeDestroy() {
cancelAnimationFrame(this.animationFrameId)
},
methods: {
handleSuccess(e, file) {
const bgImg = new Image();
bgImg.src = URL.createObjectURL(file.raw)
bgImg.crossOrigin = 'Anonymous' // 解决跨域问题(如果需要)
bgImg.onload = function () {
// 绘制背景(铺满 Canvas)
this.ctx.drawImage(bgImg, 0, 0, this.width, this.height)
// 在背景上绘制其他内容
this.ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'
this.ctx.fillRect(50, 50, 200, 100)
this.ctx.fillStyle = 'black'
this.ctx.font = '24px Arial'
this.ctx.fillText('Canvas Background', 70, 100)
}
// 处理图片加载错误
bgImg.onerror = function () {
console.error('背景图片加载失败!')
// 可以设置一个纯色备用背景
this.ctx.fillStyle = 'lightgray'
this.ctx.fillRect(0, 0, this.width, this.height)
}
},
beforeUpload(file) {
const isImage = file.type.startsWith('image/')
if (!isImage) {
this.$message.error('只能上传图片文件!')
}
return isImage // 返回 false 会阻止上传
},
initCanvas() {
const canvas = this.$refs.canvas
this.ctx = canvas.getContext('2d')
},
addRandomPoint() {
const radius = Math.floor(Math.random() * 15 + 5)
const x = Math.random() * (this.width - radius * 2) + radius
const y = Math.random() * (this.height - radius * 2) + radius
this.points.push(new Point(x, y, radius))
this.infoText = '添加了随机点位'
},
addPointAt(x, y, radius = 10) {
const point = new Point(x, y, radius)
this.points.push(point)
return point
},
clearAllPoints() {
this.points = []
this.ctx.clearRect(0, 0, this.width, this.height)
this.infoText = '已清除所有点位'
},
toggleMode() {
this.isDragCreationMode = !this.isDragCreationMode
// 取消任何进行中的拖拽
this.isDragging = false
this.currentDragPoint = null
this.infoText = `当前模式: ${
this.isDragCreationMode ? '拖拽创建点位' : '点击选择点位'
}`
},
drawAllPoints() {
this.ctx.clearRect(0, 0, this.width, this.height)
// 绘制所有已存在的点位
this.points.forEach(point => point.draw(this.ctx))
// 如果在拖拽创建模式下正在拖动,绘制临时点位
if (this.isDragCreationMode && this.isDragging && this.currentDragPoint) {
this.currentDragPoint.draw(this.ctx)
// 绘制拖拽引导线
this.ctx.beginPath()
this.ctx.moveTo(this.dragStartX, this.dragStartY)
this.ctx.lineTo(this.currentDragPoint.x, this.currentDragPoint.y)
this.ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)'
this.ctx.setLineDash([5, 3])
this.ctx.stroke()
this.ctx.setLineDash([])
}
this.animationFrameId = requestAnimationFrame(this.drawAllPoints)
},
handleClick(e) {
if (this.isDragCreationMode) return
const rect = this.$refs.canvas.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
let clickedPoint = null
// 先取消所有点位的激活状态
this.points.forEach(point => {
point.isActive = false
})
// 检查点击是否在某个点位上
for (let i = this.points.length - 1; i >= 0; i--) {
if (this.points[i].contains(x, y)) {
clickedPoint = this.points[i]
clickedPoint.isActive = true
this.infoText = `点击了点位 (${Math.round(
clickedPoint.x
)}, ${Math.round(clickedPoint.y)})`
break
}
}
if (!clickedPoint) {
this.infoText = '点击空白区域'
}
},
handleMouseDown(e) {
if (!this.isDragCreationMode) return
const rect = this.$refs.canvas.getBoundingClientRect()
this.dragStartX = e.clientX - rect.left
this.dragStartY = e.clientY - rect.top
// 检查是否点击了现有点位
let clickedExisting = false
for (let i = this.points.length - 1; i >= 0; i--) {
if (this.points[i].contains(this.dragStartX, this.dragStartY)) {
clickedExisting = true
break
}
}
if (!clickedExisting) {
this.isDragging = true
this.currentDragPoint = this.addPointAt(
this.dragStartX,
this.dragStartY,
5
)
this.infoText = '拖动鼠标调整点位大小'
}
},
handleMouseMove(e) {
if (
!this.isDragCreationMode ||
!this.isDragging ||
!this.currentDragPoint
)
return
const rect = this.$refs.canvas.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
// 计算拖拽距离作为半径
const distance = Math.sqrt(
Math.pow(x - this.dragStartX, 2) + Math.pow(y - this.dragStartY, 2)
)
this.currentDragPoint.originalRadius = Math.min(Math.max(distance, 5), 50) // 限制半径范围
this.currentDragPoint.x = this.dragStartX
this.currentDragPoint.y = this.dragStartY
},
handleMouseUp() {
if (!this.isDragCreationMode || !this.isDragging) return
this.isDragging = false
this.infoText = `已创建点位 (${Math.round(
this.currentDragPoint.x
)}, ${Math.round(this.currentDragPoint.y)}), 半径: ${Math.round(
this.currentDragPoint.originalRadius
)}`
this.currentDragPoint = null
},
handleMouseLeave() {
if (this.isDragging) {
// 如果鼠标离开画布时正在拖拽,取消当前拖拽
if (this.currentDragPoint) {
this.points.pop() // 移除未完成的点位
}
this.isDragging = false
this.currentDragPoint = null
}
}
}
}
// Point 类定义
class Point {
constructor(x, y, radius = 10) {
this.x = x
this.y = y
this.radius = radius
this.originalRadius = radius
this.color = this.getRandomColor()
this.isActive = false
}
getRandomColor() {
const r = Math.floor(Math.random() * 200 + 55)
const g = Math.floor(Math.random() * 200 + 55)
const b = Math.floor(Math.random() * 200 + 55)
return `rgb(0,0,0)`
}
draw(ctx) {
ctx.beginPath()
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2)
ctx.fillStyle = this.isActive ? '#ff0000' : this.color
ctx.fill()
ctx.strokeStyle = '#333'
ctx.stroke()
// 如果是激活状态,添加脉冲动画效果
if (this.isActive) {
this.radius = this.originalRadius * (1 + Math.sin(Date.now() / 200) * 0.2)
} else {
this.radius = this.originalRadius
}
}
contains(x, y) {
const distance = Math.sqrt((x - this.x) ** 2 + (y - this.y) ** 2)
return distance <= this.radius
}
}
</script>
<style scoped>
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
}
canvas {
background-color: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
cursor: default;
}
.controls {
margin-top: 20px;
}
.right-bar {
position: absolute;
right: 150px;
top: 20px;
}
button {
padding: 8px 16px;
margin: 0 5px;
cursor: pointer;
}
.mode-indicator {
margin-top: 10px;
font-weight: bold;
color: #333;
}
#info {
margin-top: 10px;
color: #333;
}
</style>
<template>
<div class="container">
<h1>Canvas点位交互演示</h1>
<canvas
ref="canvas"
:width="width"
:height="height"
@click="handleClick"
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@mouseleave="handleMouseLeave"
@contextmenu.prevent="handleContextMenu"
></canvas>
<div class="right-bar">
<el-upload
ref="upload"
:action="upload_url"
:before-upload="beforeUpload"
:show-file-list="false"
:auto-upload="true"
:headers="headers"
accept="image/*"
:on-success="handleSuccess"
>
<el-button slot="trigger">上传文件</el-button>
</el-upload>
</div>
<!-- 右键菜单 -->
<div
v-if="contextMenu.visible"
class="context-menu"
:style="{
left: `${contextMenu.x}px`,
top: `${contextMenu.y}px`
}"
>
<div class="menu-item" @click="changePointColor">更改颜色</div>
<div class="menu-item" @click="deletePoint">删除点位</div>
<div class="menu-item" @click="perintPoint">设置点位看板</div>
</div>
<div class="controls">
<!-- <button @click="addRandomPoint">添加随机点位</button> -->
<button @click="clearAllPoints">清除所有点位</button>
<button @click="toggleMode">
切换模式: {{ isDragCreationMode ? '点击选择' : '拖拽创建' }}
</button>
<p id="info">{{ infoText }}</p>
<p v-if="isDragCreationMode" class="mode-indicator">
在拖拽创建模式下,按住鼠标拖动可以创建点位
</p>
</div>
<!-- 颜色选择器弹窗 -->
<div v-if="colorPicker.visible" class="color-picker-modal">
<div class="color-picker">
<h3>选择新颜色</h3>
<input type="color" v-model="colorPicker.selectedColor" />
<div class="button-group">
<button @click="confirmColorChange">确定</button>
<button @click="cancelColorChange">取消</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'PointCanvasWithContextMenu',
props: {
width: {
type: Number,
default: 600
},
height: {
type: Number,
default: 400
},
initialPoints: {
type: Array,
default: () => []
}
},
data() {
return {
ctx: null,
points: [],
isDragCreationMode: false,
isDragging: false,
dragStartX: 0,
dragStartY: 0,
currentDragPoint: null,
animationFrameId: null,
infoText: '点击画布上的点位会有交互效果',
// 右键菜单相关
contextMenu: {
visible: false,
x: 0,
y: 0,
point: null
},
// 颜色选择器相关
colorPicker: {
visible: false,
selectedColor: '#ff0000',
point: null
}
}
},
mounted() {
this.initCanvas()
this.drawAllPoints()
// 添加初始点位
if (this.initialPoints.length > 0) {
this.points = this.initialPoints.map(p => new Point(p.x, p.y, p.radius))
} else {
for (let i = 0; i < 5; i++) {
this.addRandomPoint()
}
}
// 点击其他地方关闭右键菜单
document.addEventListener('click', this.closeContextMenu)
},
beforeDestroy() {
cancelAnimationFrame(this.animationFrameId)
document.removeEventListener('click', this.closeContextMenu)
},
methods: {
perintPoint() {
const index = this.points.indexOf(this.contextMenu.point)
this.$emit('perintPoint', this.points[index])
},
initCanvas() {
const canvas = this.$refs.canvas
this.ctx = canvas.getContext('2d')
},
addRandomPoint() {
const radius = Math.floor(Math.random() * 15 + 5)
const x = Math.random() * (this.width - radius * 2) + radius
const y = Math.random() * (this.height - radius * 2) + radius
this.points.push(new Point(x, y, radius))
this.infoText = '添加了随机点位'
},
addPointAt(x, y, radius = 10) {
const point = new Point(x, y, radius)
this.points.push(point)
return point
},
clearAllPoints() {
this.points = []
this.ctx.clearRect(0, 0, this.width, this.height)
this.infoText = '已清除所有点位'
},
toggleMode() {
this.isDragCreationMode = !this.isDragCreationMode
this.isDragging = false
this.currentDragPoint = null
this.infoText = `当前模式: ${
this.isDragCreationMode ? '拖拽创建点位' : '点击选择点位'
}`
},
drawAllPoints() {
this.ctx.clearRect(0, 0, this.width, this.height)
this.points.forEach(point => point.draw(this.ctx))
if (this.isDragCreationMode && this.isDragging && this.currentDragPoint) {
this.currentDragPoint.draw(this.ctx)
this.ctx.beginPath()
this.ctx.moveTo(this.dragStartX, this.dragStartY)
this.ctx.lineTo(this.currentDragPoint.x, this.currentDragPoint.y)
this.ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)'
this.ctx.setLineDash([5, 3])
this.ctx.stroke()
this.ctx.setLineDash([])
}
this.animationFrameId = requestAnimationFrame(this.drawAllPoints)
},
handleClick(e) {
if (this.isDragCreationMode) return
const rect = this.$refs.canvas.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
let clickedPoint = null
this.points.forEach(point => {
point.isActive = false
})
for (let i = this.points.length - 1; i >= 0; i--) {
if (this.points[i].contains(x, y)) {
clickedPoint = this.points[i]
clickedPoint.isActive = true
this.infoText = `点击了点位 (${Math.round(
clickedPoint.x
)}, ${Math.round(clickedPoint.y)})`
break
}
}
if (!clickedPoint) {
this.infoText = '点击空白区域'
}
},
handleMouseDown(e) {
if (!this.isDragCreationMode) return
const rect = this.$refs.canvas.getBoundingClientRect()
this.dragStartX = e.clientX - rect.left
this.dragStartY = e.clientY - rect.top
let clickedExisting = false
for (let i = this.points.length - 1; i >= 0; i--) {
if (this.points[i].contains(this.dragStartX, this.dragStartY)) {
clickedExisting = true
break
}
}
if (!clickedExisting) {
this.isDragging = true
this.currentDragPoint = this.addPointAt(
this.dragStartX,
this.dragStartY,
5
)
this.infoText = '拖动鼠标调整点位大小'
}
},
handleMouseMove(e) {
if (
!this.isDragCreationMode ||
!this.isDragging ||
!this.currentDragPoint
)
return
const rect = this.$refs.canvas.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
const distance = Math.sqrt(
Math.pow(x - this.dragStartX, 2) + Math.pow(y - this.dragStartY, 2)
)
this.currentDragPoint.originalRadius = Math.min(Math.max(distance, 5), 50)
this.currentDragPoint.x = this.dragStartX
this.currentDragPoint.y = this.dragStartY
},
handleMouseUp() {
if (!this.isDragCreationMode || !this.isDragging) return
this.isDragging = false
this.infoText = `已创建点位 (${Math.round(
this.currentDragPoint.x
)}, ${Math.round(this.currentDragPoint.y)}), 半径: ${Math.round(
this.currentDragPoint.originalRadius
)}`
this.currentDragPoint = null
},
handleMouseLeave() {
if (this.isDragging) {
if (this.currentDragPoint) {
this.points.pop()
}
this.isDragging = false
this.currentDragPoint = null
}
},
// 右键菜单相关方法
handleContextMenu(e) {
const rect = this.$refs.canvas.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
// 查找点击的点位
for (let i = this.points.length - 1; i >= 0; i--) {
if (this.points[i].contains(x, y)) {
e.preventDefault()
// 显示右键菜单
this.contextMenu = {
visible: true,
x: e.clientX,
y: e.clientY,
point: this.points[i]
}
// 高亮选中的点位
this.points.forEach(p => (p.isActive = false))
this.points[i].isActive = true
this.infoText = `右键点击了点位 (${Math.round(
this.points[i].x
)}, ${Math.round(this.points[i].y)})`
return
}
}
// 如果点击的是空白区域,隐藏右键菜单
this.closeContextMenu()
},
closeContextMenu() {
this.contextMenu.visible = false
},
// 右键菜单操作
changePointColor() {
this.colorPicker = {
visible: true,
selectedColor: this.contextMenu.point.color,
point: this.contextMenu.point
}
this.closeContextMenu()
},
deletePoint() {
const index = this.points.indexOf(this.contextMenu.point)
if (index !== -1) {
this.points.splice(index, 1)
this.infoText = `已删除点位 (${Math.round(
this.contextMenu.point.x
)}, ${Math.round(this.contextMenu.point.y)})`
}
this.closeContextMenu()
},
clonePoint() {
const original = this.contextMenu.point
const newPoint = new Point(
original.x + original.radius * 1.5,
original.y + original.radius * 1.5,
original.originalRadius
)
newPoint.color = original.color
this.points.push(newPoint)
this.infoText = `已复制点位到 (${Math.round(newPoint.x)}, ${Math.round(
newPoint.y
)})`
this.closeContextMenu()
},
addRandomPointNearby() {
const original = this.contextMenu.point
const radius = Math.floor(Math.random() * 10 + 5)
const angle = Math.random() * Math.PI * 2
const distance = original.radius * 2 + Math.random() * 50
const x = original.x + Math.cos(angle) * distance
const y = original.y + Math.sin(angle) * distance
this.addPointAt(x, y, radius)
this.infoText = `已在附近添加随机点位 (${Math.round(x)}, ${Math.round(
y
)})`
this.closeContextMenu()
},
// 颜色选择器相关方法
confirmColorChange() {
this.colorPicker.point.color = this.colorPicker.selectedColor
this.colorPicker.visible = false
this.infoText = `已更改点位颜色为 ${this.colorPicker.selectedColor}`
},
cancelColorChange() {
this.colorPicker.visible = false
}
}
}
class Point {
constructor(x, y, radius = 10) {
this.x = x
this.y = y
this.radius = radius
this.originalRadius = radius
this.color = this.getRandomColor()
this.isActive = false
}
getRandomColor() {
const r = Math.floor(Math.random() * 200 + 55)
const g = Math.floor(Math.random() * 200 + 55)
const b = Math.floor(Math.random() * 200 + 55)
return `rgb(${r}, ${g}, ${b})`
}
draw(ctx) {
ctx.beginPath()
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2)
ctx.fillStyle = this.isActive ? '#ff0000' : this.color
ctx.fill()
ctx.strokeStyle = '#333'
ctx.stroke()
if (this.isActive) {
this.radius = this.originalRadius * (1 + Math.sin(Date.now() / 200) * 0.2)
} else {
this.radius = this.originalRadius
}
}
contains(x, y) {
const distance = Math.sqrt((x - this.x) ** 2 + (y - this.y) ** 2)
return distance <= this.radius
}
}
</script>
<style scoped>
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
position: relative;
}
canvas {
background-color: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
cursor: default;
}
.controls {
margin-top: 20px;
}
button {
padding: 8px 16px;
margin: 0 5px;
cursor: pointer;
}
.mode-indicator {
margin-top: 10px;
font-weight: bold;
color: #333;
}
#info {
margin-top: 10px;
color: #333;
}
/* 右键菜单样式 */
.context-menu {
position: fixed;
background-color: white;
border: 1px solid #ddd;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
border-radius: 4px;
z-index: 1000;
min-width: 150px;
}
.menu-item {
padding: 8px 12px;
cursor: pointer;
}
.menu-item:hover {
background-color: #f5f5f5;
}
/* 颜色选择器弹窗 */
.color-picker-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1001;
}
.color-picker {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
}
.color-picker h3 {
margin-top: 0;
}
.color-picker input[type='color'] {
width: 100%;
margin: 10px 0;
}
.button-group {
display: flex;
justify-content: space-between;
}
.button-group button {
flex: 1;
margin: 0 5px;
}
.right-bar {
position: absolute;
right: 150px;
top: 20px;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment