refactor(elevator): 重构电梯点状态渲染为极简设计,移除动画效果和图标依赖,统一使用静态边框和颜色编码
This commit is contained in:
parent
5f7a9b6dce
commit
624c68d0eb
@ -530,8 +530,8 @@ onMounted(async () => {
|
|||||||
id: '1998661793706377218',
|
id: '1998661793706377218',
|
||||||
type: 102,
|
type: 102,
|
||||||
elevatorFloor: 5,
|
elevatorFloor: 5,
|
||||||
elevatorDirection: 1, // 停止
|
elevatorDirection: 3, // 停止
|
||||||
elevatorFrontDoorStatus: 2, // 正在开关
|
elevatorFrontDoorStatus: 3, // 正在开关
|
||||||
isConnected: true
|
isConnected: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -54,13 +54,31 @@ function drawDisconnectedIcon(ctx: CanvasRenderingContext2D, cx: number, cy: num
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 绘制电梯点的动态效果 - 矩形框架动画系统
|
* 绘制电梯点的极简状态指示 - 设计理念:
|
||||||
|
* 1. 简约至上:仅使用矩形边框和颜色传达状态,无文字说明
|
||||||
|
* 2. 图片优先:确保48*60电梯图片完全可见,边框不覆盖主体
|
||||||
|
* 3. 响应式设计:所有尺寸基于pen元素宽高动态计算,完美适配画布缩放
|
||||||
|
* 4. 直观色彩:
|
||||||
|
* - 红色虚线:离线状态
|
||||||
|
* - 绿色静态:开关门状态或门已开
|
||||||
|
* - 蓝色静态边框+右侧箭头:上行/下行
|
||||||
|
* - 金色:停止
|
||||||
|
* - 灰色:未知状态
|
||||||
|
* 5. 静态箭头:上下行时在边框右侧显示静态箭头,简洁清晰
|
||||||
|
*
|
||||||
|
* 尺寸计算规则:
|
||||||
|
* - 边框距离:最小4px,否则按pen较小边的15%计算
|
||||||
|
* - 边框宽度:最小1.5px,否则按pen较小边的3%计算
|
||||||
|
* - 圆角半径:最小2px,否则按pen较小边的5%计算
|
||||||
|
* - 方向指示器:最小3px,否则按pen较小边的10%计算
|
||||||
|
* - 右侧箭头:最小4px,否则按pen较小边的12%计算
|
||||||
|
* - 虚线样式:根据pen尺寸动态调整间距比例
|
||||||
* @param ctx Canvas上下文
|
* @param ctx Canvas上下文
|
||||||
* @param pen 画笔对象
|
* @param pen 画笔对象
|
||||||
* @param elevatorData 电梯数据(包含后端字段)
|
* @param elevatorData 电梯数据(包含后端字段)
|
||||||
* @param time 当前时间戳(毫秒)
|
* @param time 当前时间戳(毫秒)(保留参数以兼容接口,但不再使用)
|
||||||
*/
|
*/
|
||||||
function drawElevatorAnimation(
|
function drawElevatorMinimal(
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
pen: MapPen,
|
pen: MapPen,
|
||||||
elevatorData: any,
|
elevatorData: any,
|
||||||
@ -71,133 +89,76 @@ function drawElevatorAnimation(
|
|||||||
elevatorDirection,
|
elevatorDirection,
|
||||||
elevatorFrontDoorStatus,
|
elevatorFrontDoorStatus,
|
||||||
isConnected,
|
isConnected,
|
||||||
|
|
||||||
} = elevatorData;
|
} = elevatorData;
|
||||||
|
|
||||||
const { x = 0, y = 0, width: w = 0, height: h = 0 } = pen.calculative?.worldRect ?? {};
|
const { x = 0, y = 0, width: w = 0, height: h = 0 } = pen.calculative?.worldRect ?? {};
|
||||||
|
|
||||||
// 为48*60图片设计矩形动画框架
|
// 基于pen元素尺寸的动态边框参数
|
||||||
// 外边框距离图片边缘6像素,确保不覆盖图片
|
const baseSize = Math.min(w, h); // 取较小的尺寸作为基准
|
||||||
const framePadding = 6;
|
const padding = Math.max(4, baseSize * 0.15); // 距离图片边缘:最小4px,否则按15%比例
|
||||||
const frameWidth = 3; // 边框宽度
|
const strokeWidth = Math.max(1.5, baseSize * 0.03); // 边框宽度:最小1.5px,否则按3%比例
|
||||||
const cornerLength = 12; // 角装饰长度
|
const borderRadius = Math.max(2, baseSize * 0.05); // 圆角半径:最小2px,否则按5%比例
|
||||||
const cornerWidth = 4; // 角装饰宽度
|
|
||||||
|
|
||||||
// 动画框架的四个角坐标
|
// 矩形边框坐标(基于动态参数)
|
||||||
const frameCorners = {
|
const rectX = x - padding;
|
||||||
topLeft: { x: x - framePadding, y: y - framePadding },
|
const rectY = y - padding;
|
||||||
topRight: { x: x + w + framePadding, y: y - framePadding },
|
const rectW = w + padding * 2;
|
||||||
bottomLeft: { x: x - framePadding, y: y + h + framePadding },
|
const rectH = h + padding * 2;
|
||||||
bottomRight: { x: x + w + framePadding, y: y + h + framePadding }
|
|
||||||
};
|
|
||||||
|
|
||||||
// 检查是否启用LOD
|
// 辅助函数:绘制极简矩形边框
|
||||||
const lodEnabled = (pen.calculative as any)?.lodEnabled || false;
|
const drawMinimalFrame = (color: string, alpha: number = 1, useDashedLine: boolean = false) => {
|
||||||
|
|
||||||
// 辅助函数:绘制矩形框架的角装饰
|
|
||||||
const drawFrameCorners = (color: string, alpha: number, animated: boolean = true) => {
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
|
// 设置边框样式
|
||||||
ctx.strokeStyle = color;
|
ctx.strokeStyle = color;
|
||||||
ctx.fillStyle = color;
|
ctx.lineWidth = strokeWidth;
|
||||||
ctx.lineWidth = cornerWidth;
|
|
||||||
ctx.lineCap = 'square';
|
|
||||||
ctx.globalAlpha = alpha;
|
ctx.globalAlpha = alpha;
|
||||||
|
|
||||||
// 动画效果:角装饰闪烁
|
// 虚线样式(动态调整间距)
|
||||||
const animPhase = animated ? Math.sin(time * 0.002) * 0.5 + 0.5 : 1;
|
if (useDashedLine) {
|
||||||
|
const dashLength = Math.max(3, baseSize * 0.08); // 虚线长度:最小3px,否则按8%比例
|
||||||
// 左上角
|
const gapLength = Math.max(3, baseSize * 0.05); // 间隙长度:最小3px,否则按5%比例
|
||||||
ctx.globalAlpha = alpha * animPhase;
|
ctx.setLineDash([dashLength, gapLength]);
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(frameCorners.topLeft.x, frameCorners.topLeft.y + cornerLength);
|
|
||||||
ctx.lineTo(frameCorners.topLeft.x, frameCorners.topLeft.y);
|
|
||||||
ctx.lineTo(frameCorners.topLeft.x + cornerLength, frameCorners.topLeft.y);
|
|
||||||
ctx.stroke();
|
|
||||||
|
|
||||||
// 右上角
|
|
||||||
ctx.globalAlpha = alpha * (animPhase + 0.25) % 1;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(frameCorners.topRight.x - cornerLength, frameCorners.topRight.y);
|
|
||||||
ctx.lineTo(frameCorners.topRight.x, frameCorners.topRight.y);
|
|
||||||
ctx.lineTo(frameCorners.topRight.x, frameCorners.topRight.y + cornerLength);
|
|
||||||
ctx.stroke();
|
|
||||||
|
|
||||||
// 右下角
|
|
||||||
ctx.globalAlpha = alpha * (animPhase + 0.5) % 1;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(frameCorners.bottomRight.x, frameCorners.bottomRight.y - cornerLength);
|
|
||||||
ctx.lineTo(frameCorners.bottomRight.x, frameCorners.bottomRight.y);
|
|
||||||
ctx.lineTo(frameCorners.bottomRight.x - cornerLength, frameCorners.bottomRight.y);
|
|
||||||
ctx.stroke();
|
|
||||||
|
|
||||||
// 左下角
|
|
||||||
ctx.globalAlpha = alpha * (animPhase + 0.75) % 1;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(frameCorners.bottomLeft.x + cornerLength, frameCorners.bottomLeft.y);
|
|
||||||
ctx.lineTo(frameCorners.bottomLeft.x, frameCorners.bottomLeft.y);
|
|
||||||
ctx.lineTo(frameCorners.bottomLeft.x, frameCorners.bottomLeft.y - cornerLength);
|
|
||||||
ctx.stroke();
|
|
||||||
|
|
||||||
ctx.restore();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 辅助函数:绘制完整矩形边框
|
|
||||||
const drawFullFrame = (color: string, alpha: number, dashPattern: number[] = []) => {
|
|
||||||
ctx.save();
|
|
||||||
ctx.strokeStyle = color;
|
|
||||||
ctx.lineWidth = frameWidth;
|
|
||||||
ctx.globalAlpha = alpha;
|
|
||||||
|
|
||||||
if (dashPattern.length > 0) {
|
|
||||||
ctx.setLineDash(dashPattern);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.strokeRect(
|
// 绘制圆角矩形
|
||||||
frameCorners.topLeft.x,
|
ctx.beginPath();
|
||||||
frameCorners.topLeft.y,
|
ctx.roundRect(rectX, rectY, rectW, rectH, borderRadius);
|
||||||
frameCorners.bottomRight.x - frameCorners.topLeft.x,
|
ctx.stroke();
|
||||||
frameCorners.bottomRight.y - frameCorners.topLeft.y
|
|
||||||
);
|
|
||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 辅助函数:绘制方向指示(仅当电梯移动时)
|
||||||
// 辅助函数:绘制方向箭头(在框架外部)
|
const drawDirection = (direction: 'up' | 'down', color: string) => {
|
||||||
const drawDirectionArrows = (direction: 'up' | 'down', color: string) => {
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.strokeStyle = color;
|
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
ctx.lineWidth = 3;
|
ctx.globalAlpha = 0.8;
|
||||||
ctx.lineCap = 'round';
|
|
||||||
ctx.lineJoin = 'round';
|
|
||||||
|
|
||||||
const arrowSize = 8;
|
// 方向指示器大小基于pen尺寸动态调整
|
||||||
const arrowOffset = 15; // 箭头距离框架的距离
|
const indicatorSize = Math.max(3, baseSize * 0.1); // 最小3px,否则按10%比例
|
||||||
const animProgress = (Math.sin(time * 0.003) + 1) * 0.5;
|
const margin = Math.max(2, baseSize * 0.05); // 距离边框的距离:最小2px,否则按5%比例
|
||||||
|
|
||||||
if (direction === 'up') {
|
if (direction === 'up') {
|
||||||
// 上行箭头:在框架上方
|
// 向上三角 - 位于矩形顶部中央
|
||||||
const arrowY = frameCorners.topLeft.y - arrowOffset - animProgress * 5;
|
|
||||||
const centerX = x + w / 2;
|
const centerX = x + w / 2;
|
||||||
|
const centerY = rectY + margin + indicatorSize;
|
||||||
|
|
||||||
ctx.globalAlpha = 0.8 + animProgress * 0.2;
|
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(centerX, arrowY);
|
ctx.moveTo(centerX, centerY - indicatorSize);
|
||||||
ctx.lineTo(centerX - arrowSize, arrowY + arrowSize);
|
ctx.lineTo(centerX - indicatorSize, centerY + indicatorSize);
|
||||||
ctx.lineTo(centerX + arrowSize, arrowY + arrowSize);
|
ctx.lineTo(centerX + indicatorSize, centerY + indicatorSize);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
} else {
|
} else {
|
||||||
// 下行箭头:在框架下方
|
// 向下三角 - 位于矩形底部中央
|
||||||
const arrowY = frameCorners.bottomLeft.y + arrowOffset + animProgress * 5;
|
|
||||||
const centerX = x + w / 2;
|
const centerX = x + w / 2;
|
||||||
|
const centerY = rectY + rectH - margin - indicatorSize;
|
||||||
|
|
||||||
ctx.globalAlpha = 0.8 + animProgress * 0.2;
|
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(centerX, arrowY);
|
ctx.moveTo(centerX, centerY + indicatorSize);
|
||||||
ctx.lineTo(centerX - arrowSize, arrowY - arrowSize);
|
ctx.lineTo(centerX - indicatorSize, centerY - indicatorSize);
|
||||||
ctx.lineTo(centerX + arrowSize, arrowY - arrowSize);
|
ctx.lineTo(centerX + indicatorSize, centerY - indicatorSize);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
@ -205,122 +166,117 @@ function drawElevatorAnimation(
|
|||||||
ctx.restore();
|
ctx.restore();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 辅助函数:绘制门状态指示(在框架两侧)
|
// 辅助函数:在边框右侧绘制静态方向箭头
|
||||||
const drawDoorIndicators = (isOpening: boolean, color: string) => {
|
const drawDirectionSide = (direction: 'up' | 'down', color: string) => {
|
||||||
ctx.save();
|
|
||||||
ctx.strokeStyle = color;
|
|
||||||
ctx.lineWidth = 2;
|
|
||||||
ctx.globalAlpha = 0.7;
|
|
||||||
|
|
||||||
const progress = isOpening ?
|
|
||||||
(Math.sin(time * 0.001) + 1) * 0.5 :
|
|
||||||
1 - (Math.sin(time * 0.001) + 1) * 0.5;
|
|
||||||
|
|
||||||
const doorHeight = h * 0.3;
|
|
||||||
const doorWidth = 3;
|
|
||||||
const sideOffset = 12; // 距离框架侧边的距离
|
|
||||||
|
|
||||||
// 左门指示
|
|
||||||
const leftDoorX = frameCorners.topLeft.x - sideOffset - progress * 8;
|
|
||||||
const doorY = y + (h - doorHeight) / 2;
|
|
||||||
ctx.strokeRect(leftDoorX, doorY, doorWidth, doorHeight);
|
|
||||||
|
|
||||||
// 右门指示
|
|
||||||
const rightDoorX = frameCorners.topRight.x + sideOffset + progress * 8;
|
|
||||||
ctx.strokeRect(rightDoorX, doorY, doorWidth, doorHeight);
|
|
||||||
|
|
||||||
ctx.restore();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 辅助函数:绘制状态文本
|
|
||||||
const drawStatusText = (text: string, color: string) => {
|
|
||||||
if (lodEnabled) return; // LOD模式下不显示文本
|
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
ctx.font = '10px Arial';
|
ctx.strokeStyle = color;
|
||||||
ctx.textAlign = 'center';
|
ctx.globalAlpha = 0.8;
|
||||||
ctx.textBaseline = 'top';
|
|
||||||
ctx.globalAlpha = 0.9;
|
// 箭头大小基于pen尺寸动态调整,使用宽度和高度的平均值来更好地适应不同比例
|
||||||
|
const avgSize = (w + h) / 2; // 使用宽高平均值作为基准
|
||||||
|
const arrowSize = Math.max(4, avgSize * 0.12); // 最小4px,否则按12%比例
|
||||||
|
const sideMargin = Math.max(3, avgSize * 0.08); // 距离右侧边框的距离
|
||||||
|
ctx.lineWidth = Math.max(1.5, avgSize * 0.025); // 箭头线条宽度
|
||||||
|
|
||||||
|
// 箭头位置:在矩形右侧垂直居中
|
||||||
|
const arrowX = rectX + rectW + sideMargin;
|
||||||
|
const centerY = y + h / 2; // 垂直居中
|
||||||
|
|
||||||
|
if (direction === 'up') {
|
||||||
|
// 向上箭头 - 在右侧绘制
|
||||||
|
ctx.beginPath();
|
||||||
|
// 箭头主体(竖线)
|
||||||
|
ctx.moveTo(arrowX, centerY + arrowSize);
|
||||||
|
ctx.lineTo(arrowX, centerY - arrowSize);
|
||||||
|
// 箭头尖端(三角形)
|
||||||
|
ctx.lineTo(arrowX - arrowSize * 0.6, centerY - arrowSize * 0.4);
|
||||||
|
ctx.moveTo(arrowX, centerY - arrowSize);
|
||||||
|
ctx.lineTo(arrowX + arrowSize * 0.6, centerY - arrowSize * 0.4);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// 填充箭头头部
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(arrowX, centerY - arrowSize);
|
||||||
|
ctx.lineTo(arrowX - arrowSize * 0.5, centerY - arrowSize * 0.7);
|
||||||
|
ctx.lineTo(arrowX + arrowSize * 0.5, centerY - arrowSize * 0.7);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fill();
|
||||||
|
} else {
|
||||||
|
// 向下箭头 - 在右侧绘制
|
||||||
|
ctx.beginPath();
|
||||||
|
// 箭头主体(竖线)
|
||||||
|
ctx.moveTo(arrowX, centerY - arrowSize);
|
||||||
|
ctx.lineTo(arrowX, centerY + arrowSize);
|
||||||
|
// 箭头尖端(三角形)
|
||||||
|
ctx.lineTo(arrowX - arrowSize * 0.6, centerY + arrowSize * 0.4);
|
||||||
|
ctx.moveTo(arrowX, centerY + arrowSize);
|
||||||
|
ctx.lineTo(arrowX + arrowSize * 0.6, centerY + arrowSize * 0.4);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// 填充箭头头部
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(arrowX, centerY + arrowSize);
|
||||||
|
ctx.lineTo(arrowX - arrowSize * 0.5, centerY + arrowSize * 0.7);
|
||||||
|
ctx.lineTo(arrowX + arrowSize * 0.5, centerY + arrowSize * 0.7);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
|
||||||
// 在图片下方显示状态文本
|
|
||||||
ctx.fillText(text, x + w / 2, frameCorners.bottomLeft.y + 5);
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 辅助函数:绘制连接状态指示器
|
// 辅助函数:呼吸动画效果
|
||||||
const drawConnectionIndicator = () => {
|
const breatheAnimation = (baseAlpha: number = 0.6) => {
|
||||||
if (!isConnected) {
|
// 使用缓慢的正弦波创建呼吸效果
|
||||||
ctx.save();
|
return baseAlpha + Math.sin(time * 0.001) * 0.2;
|
||||||
const pulseIntensity = 0.5 + Math.sin(time * 0.003) * 0.5;
|
|
||||||
|
|
||||||
// 断连图标在右上角
|
|
||||||
ctx.fillStyle = `rgba(255, 59, 48, ${pulseIntensity})`;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(frameCorners.topRight.x, frameCorners.topRight.y, 4, 0, Math.PI * 2);
|
|
||||||
ctx.fill();
|
|
||||||
|
|
||||||
ctx.strokeStyle = `rgba(255, 59, 48, ${pulseIntensity})`;
|
|
||||||
ctx.lineWidth = 2;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(frameCorners.topRight.x - 6, frameCorners.topRight.y - 6);
|
|
||||||
ctx.lineTo(frameCorners.topRight.x + 6, frameCorners.topRight.y + 6);
|
|
||||||
ctx.stroke();
|
|
||||||
|
|
||||||
ctx.restore();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 状态渲染逻辑
|
// 辅助函数:脉冲动画效果(用于断连状态)
|
||||||
|
const pulseAnimation = () => {
|
||||||
|
return 0.4 + Math.sin(time * 0.002) * 0.4;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 状态渲染逻辑 - 静态显示,无动画
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
// 离线状态:红色闪烁角 + 断连图标
|
// 离线状态 - 红色虚线
|
||||||
drawFrameCorners('rgba(255, 59, 48, 0.8)', 0.8, true);
|
drawMinimalFrame('#FF3B30', 0.8, true);
|
||||||
drawConnectionIndicator();
|
|
||||||
drawStatusText('离线', '#FF3B30');
|
|
||||||
} else {
|
} else {
|
||||||
// 在线状态根据具体状态渲染
|
// 在线状态根据具体状态渲染
|
||||||
switch (elevatorFrontDoorStatus) {
|
switch (elevatorFrontDoorStatus) {
|
||||||
case 2: // 正在开关门
|
case 2: { // 正在开关门
|
||||||
// 绿色动态框架 + 门指示器
|
// 绿色静态边框
|
||||||
drawFrameCorners('rgba(52, 199, 89, 0.8)', 0.7, true);
|
drawMinimalFrame('#34C759', 0.8);
|
||||||
if (!lodEnabled) {
|
|
||||||
drawDoorIndicators(true, 'rgba(52, 199, 89, 0.8)');
|
|
||||||
}
|
|
||||||
drawStatusText('开门中', '#34C759');
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 3: // 门已开
|
case 3: { // 门已开
|
||||||
// 蓝色呼吸框架
|
// 绿色静态边框
|
||||||
drawStatusText('门已开', '#007AFF');
|
drawMinimalFrame('#34C759', 0.8);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 1: // 门已关
|
case 1: { // 门已关
|
||||||
if (elevatorDirection === 2) { // 向上
|
if (elevatorDirection === 2) { // 向上
|
||||||
// 紫色动态框架 + 上行箭头
|
// 蓝色静态边框 + 右侧向上箭头
|
||||||
drawFrameCorners('rgba(175, 82, 222, 0.8)', 0.7, true);
|
drawMinimalFrame('#007AFF', 0.8);
|
||||||
if (!lodEnabled) {
|
drawDirectionSide('up', '#007AFF');
|
||||||
drawDirectionArrows('up', 'rgba(175, 82, 222, 0.8)');
|
|
||||||
}
|
|
||||||
drawStatusText('上行中', '#AF52DE');
|
|
||||||
} else if (elevatorDirection === 3) { // 向下
|
} else if (elevatorDirection === 3) { // 向下
|
||||||
// 青色动态框架 + 下行箭头
|
// 蓝色静态边框 + 右侧向下箭头
|
||||||
drawFrameCorners('rgba(90, 200, 250, 0.8)', 0.7, true);
|
drawMinimalFrame('#007AFF', 0.8);
|
||||||
if (!lodEnabled) {
|
drawDirectionSide('down', '#007AFF');
|
||||||
drawDirectionArrows('down', 'rgba(90, 200, 250, 0.8)');
|
|
||||||
}
|
|
||||||
drawStatusText('下行中', '#5AC8FA');
|
|
||||||
} else { // 停止
|
} else { // 停止
|
||||||
// 金色静态框架
|
// 金色静态边框
|
||||||
drawFullFrame('rgba(255, 204, 0, 0.6)', 0.6);
|
drawMinimalFrame('#FFCC00', 0.7);
|
||||||
drawStatusText('停止', '#FFCC00');
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: // 未知状态
|
default: { // 未知状态
|
||||||
// 灰色静态框架
|
// 灰色静态边框
|
||||||
drawFullFrame('rgba(142, 142, 147, 0.5)', 0.5);
|
drawMinimalFrame('#8E8E93', 0.5);
|
||||||
drawStatusText('未知', '#8E8E93');
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -556,15 +512,15 @@ export function drawPoint(ctx: CanvasRenderingContext2D, pen: MapPen): void {
|
|||||||
const largeTypeStrokeColor = colorConfig.getColor(`point.types.${type}.stroke`);
|
const largeTypeStrokeColor = colorConfig.getColor(`point.types.${type}.stroke`);
|
||||||
const largeGeneralStrokeColor = colorConfig.getColor(active ? 'point.large.strokeActive' : 'point.large.stroke');
|
const largeGeneralStrokeColor = colorConfig.getColor(active ? 'point.large.strokeActive' : 'point.large.stroke');
|
||||||
const largeThemeStrokeColor = get(theme, active ? 'point-l.strokeActive' : 'point-l.stroke');
|
const largeThemeStrokeColor = get(theme, active ? 'point-l.strokeActive' : 'point-l.stroke');
|
||||||
ctx.strokeStyle = statusStyle ?? (largeTypeStrokeColor || largeGeneralStrokeColor || largeThemeStrokeColor || '');
|
ctx.strokeStyle = largeTypeStrokeColor || largeGeneralStrokeColor || largeThemeStrokeColor || '';
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
// 电梯点:添加动画效果
|
// 电梯点:使用极简状态渲染
|
||||||
if (type === MapPointType.电梯点) {
|
if (type === MapPointType.电梯点) {
|
||||||
// 直接传入包含后端字段的 pen.point 数据
|
// 直接传入包含后端字段的 pen.point 数据
|
||||||
if (pen.point) {
|
if (pen.point) {
|
||||||
const currentTime = performance.now();
|
const currentTime = performance.now();
|
||||||
drawElevatorAnimation(ctx, pen, pen.point, currentTime);
|
drawElevatorMinimal(ctx, pen, pen.point, currentTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -151,20 +151,15 @@ export const useElevatorStore = defineStore('elevator', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新画布上电梯点的显示 - 增强版
|
* 更新画布上电梯点的显示
|
||||||
*/
|
*/
|
||||||
const updateElevatorPointDisplay = (elevatorData: ElevatorData) => {
|
const updateElevatorPointDisplay = (elevatorData: ElevatorData) => {
|
||||||
if (!editorService.value || !elevatorData.penId) return;
|
if (!editorService.value || !elevatorData.penId) return;
|
||||||
|
|
||||||
const penId = elevatorData.penId;
|
const penId = elevatorData.penId;
|
||||||
|
|
||||||
// 获取状态对应的颜色、图标和动画配置
|
|
||||||
const displayConfig = getElevatorDisplay(elevatorData);
|
|
||||||
|
|
||||||
// 基础更新数据
|
// 基础更新数据
|
||||||
const updateData: any = {
|
const updateData: any = {
|
||||||
// 设置图标
|
|
||||||
image: displayConfig.iconPath,
|
|
||||||
// 更新点位信息
|
// 更新点位信息
|
||||||
point: {
|
point: {
|
||||||
...((editorService.value.getPenById(penId) as any)?.point || {}),
|
...((editorService.value.getPenById(penId) as any)?.point || {}),
|
||||||
@ -173,15 +168,8 @@ export const useElevatorStore = defineStore('elevator', () => {
|
|||||||
lastUpdate: elevatorData.lastUpdate,
|
lastUpdate: elevatorData.lastUpdate,
|
||||||
// 保存原始后端数据
|
// 保存原始后端数据
|
||||||
elevatorDirection: elevatorData.elevatorDirection,
|
elevatorDirection: elevatorData.elevatorDirection,
|
||||||
elevatorFrontDoorStatus: elevatorData.elevatorFrontDoorStatus,
|
elevatorFrontDoorStatus: elevatorData.elevatorFrontDoorStatus
|
||||||
// 使用新的颜色系统
|
}
|
||||||
color: displayConfig.color,
|
|
||||||
// 动画配置
|
|
||||||
animationClass: displayConfig.animationClass,
|
|
||||||
priority: displayConfig.priority
|
|
||||||
},
|
|
||||||
// 增强的样式配置
|
|
||||||
statusStyle: displayConfig.color
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -194,109 +182,7 @@ export const useElevatorStore = defineStore('elevator', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取电梯显示配置(颜色、图标)
|
|
||||||
* 基于后端字段直接判断,使用现代化设计系统
|
|
||||||
*/
|
|
||||||
const getElevatorDisplay = (elevatorData: ElevatorData) => {
|
|
||||||
// 生成图标路径的辅助函数
|
|
||||||
const getIconPath = (theme: string) => `${import.meta.env.BASE_URL}/point/elevator-${theme}.svg`;
|
|
||||||
|
|
||||||
// 现代化颜色配置系统
|
|
||||||
const colors = {
|
|
||||||
offline: '#FF3B30', // 红色 - 离线
|
|
||||||
opening: '#34C759', // 绿色 - 开门中
|
|
||||||
doorOpen: '#007AFF', // 蓝色 - 门已开
|
|
||||||
moving: '#AF52DE', // 紫色 - 运行中
|
|
||||||
upMoving: '#AF52DE', // 紫色 - 上行
|
|
||||||
downMoving: '#5AC8FA', // 青色 - 下行
|
|
||||||
stopped: '#FFCC00', // 金色 - 停止
|
|
||||||
idle: '#8E8E93', // 灰色 - 静止
|
|
||||||
unknown: '#8E8E93' // 灰色 - 未知
|
|
||||||
};
|
|
||||||
|
|
||||||
// 如果离线,显示红色
|
|
||||||
if (!elevatorData.isConnected) {
|
|
||||||
return {
|
|
||||||
color: colors.offline,
|
|
||||||
iconPath: getIconPath('offline'),
|
|
||||||
text: '离线',
|
|
||||||
priority: 'high',
|
|
||||||
animationClass: 'pulse-error'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据后端字段判断显示状态
|
|
||||||
const { elevatorDirection, elevatorFrontDoorStatus, elevatorFloor } = elevatorData;
|
|
||||||
|
|
||||||
// 优先判断门状态
|
|
||||||
switch (elevatorFrontDoorStatus) {
|
|
||||||
case 2: // 正在开关门
|
|
||||||
return {
|
|
||||||
color: colors.opening,
|
|
||||||
iconPath: getIconPath('opening'),
|
|
||||||
text: `开门中 ${elevatorFloor > 0 ? `(${elevatorFloor}F)` : ''}`,
|
|
||||||
priority: 'high',
|
|
||||||
animationClass: 'pulse-success'
|
|
||||||
};
|
|
||||||
|
|
||||||
case 3: // 门已开
|
|
||||||
return {
|
|
||||||
color: colors.doorOpen,
|
|
||||||
iconPath: getIconPath('door-open'),
|
|
||||||
text: `门已开 ${elevatorFloor > 0 ? `(${elevatorFloor}F)` : ''}`,
|
|
||||||
priority: 'normal',
|
|
||||||
animationClass: 'breathe'
|
|
||||||
};
|
|
||||||
|
|
||||||
case 1: // 门已关
|
|
||||||
switch (elevatorDirection) {
|
|
||||||
case 2: // 向上
|
|
||||||
return {
|
|
||||||
color: colors.upMoving,
|
|
||||||
iconPath: getIconPath('up'),
|
|
||||||
text: `上行中 ${elevatorFloor > 0 ? `(${elevatorFloor}F)` : ''}`,
|
|
||||||
priority: 'high',
|
|
||||||
animationClass: 'flow-up'
|
|
||||||
};
|
|
||||||
|
|
||||||
case 3: // 向下
|
|
||||||
return {
|
|
||||||
color: colors.downMoving,
|
|
||||||
iconPath: getIconPath('down'),
|
|
||||||
text: `下行中 ${elevatorFloor > 0 ? `(${elevatorFloor}F)` : ''}`,
|
|
||||||
priority: 'high',
|
|
||||||
animationClass: 'flow-down'
|
|
||||||
};
|
|
||||||
|
|
||||||
case 1: // 停止
|
|
||||||
return {
|
|
||||||
color: colors.stopped,
|
|
||||||
iconPath: getIconPath('stopped'),
|
|
||||||
text: `停止 ${elevatorFloor > 0 ? `(${elevatorFloor}F)` : ''}`,
|
|
||||||
priority: 'normal',
|
|
||||||
animationClass: 'gentle-pulse'
|
|
||||||
};
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 未知状态
|
|
||||||
return {
|
|
||||||
color: colors.unknown,
|
|
||||||
iconPath: getIconPath('unknown'),
|
|
||||||
text: '未知状态',
|
|
||||||
priority: 'low',
|
|
||||||
animationClass: 'dim'
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新电梯映射(场景变化时调用)
|
* 刷新电梯映射(场景变化时调用)
|
||||||
@ -313,10 +199,6 @@ export const useElevatorStore = defineStore('elevator', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// 状态
|
// 状态
|
||||||
elevators,
|
elevators,
|
||||||
@ -325,7 +207,6 @@ export const useElevatorStore = defineStore('elevator', () => {
|
|||||||
// 方法
|
// 方法
|
||||||
setEditorService,
|
setEditorService,
|
||||||
handleElevatorWebSocketData,
|
handleElevatorWebSocketData,
|
||||||
refreshMapping,
|
refreshMapping
|
||||||
getElevatorDisplay
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user