feat(elevator): 使用Canvas绘制电梯图标并集成动画效果,移除外部边框和箭头以简化状态显示
This commit is contained in:
parent
d975357f04
commit
0a1608262d
@ -53,10 +53,265 @@ function drawDisconnectedIcon(ctx: CanvasRenderingContext2D, cx: number, cy: num
|
|||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用Canvas绘制电梯图标(48*60像素)并实现开门关门动画
|
||||||
|
* @param ctx Canvas上下文
|
||||||
|
* @param cx 中心X坐标
|
||||||
|
* @param cy 中心Y坐标
|
||||||
|
* @param width 电梯宽度(默认48)
|
||||||
|
* @param height 电梯高度(默认60)
|
||||||
|
* @param doorStatus 门状态(1-关,2-正在开关,3-开)
|
||||||
|
* @param time 当前时间戳(用于动画)
|
||||||
|
* @param direction 电梯方向(0-未知,1-停止,2-向上,3-向下)
|
||||||
|
*/
|
||||||
|
function drawElevatorIcon(
|
||||||
|
ctx: CanvasRenderingContext2D,
|
||||||
|
cx: number,
|
||||||
|
cy: number,
|
||||||
|
width: number = 48,
|
||||||
|
height: number = 60,
|
||||||
|
doorStatus: number = 1,
|
||||||
|
time: number = 0,
|
||||||
|
direction: number = 0
|
||||||
|
): void {
|
||||||
|
const x = cx - width / 2;
|
||||||
|
const y = cy - height / 2;
|
||||||
|
|
||||||
|
// 电梯外框 - 金属质感
|
||||||
|
const gradient = ctx.createLinearGradient(x, y, x + width, y + height);
|
||||||
|
gradient.addColorStop(0, '#9ca3af'); // 浅灰色
|
||||||
|
gradient.addColorStop(0.5, '#6b7280'); // 中灰色
|
||||||
|
gradient.addColorStop(1, '#4b5563'); // 深灰色
|
||||||
|
ctx.fillStyle = gradient;
|
||||||
|
ctx.fillRect(x, y, width, height);
|
||||||
|
|
||||||
|
// 电梯内框 - 深金属色
|
||||||
|
const innerGradient = ctx.createLinearGradient(x + 2, y + 2, x + width - 2, y + height - 2);
|
||||||
|
innerGradient.addColorStop(0, '#374151');
|
||||||
|
innerGradient.addColorStop(0.5, '#1f2937');
|
||||||
|
innerGradient.addColorStop(1, '#111827');
|
||||||
|
ctx.fillStyle = innerGradient;
|
||||||
|
ctx.fillRect(x + 2, y + 2, width - 4, height - 4);
|
||||||
|
|
||||||
|
// 计算门的开合程度(0-1之间)
|
||||||
|
let doorProgress = 0;
|
||||||
|
if (doorStatus === 1) {
|
||||||
|
doorProgress = 0; // 完全关闭
|
||||||
|
} else if (doorStatus === 3) {
|
||||||
|
doorProgress = 1; // 完全打开
|
||||||
|
} else if (doorStatus === 2) {
|
||||||
|
// 正在开关门,使用动画
|
||||||
|
const animationDuration = 2000; // 2秒完成开关门
|
||||||
|
const phase = (time % animationDuration) / animationDuration;
|
||||||
|
// 使用正弦函数创建平滑的往复运动
|
||||||
|
doorProgress = (Math.sin(phase * Math.PI * 2 - Math.PI / 2) + 1) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 门的位置
|
||||||
|
const doorWidth = (width - 8) / 2;
|
||||||
|
const doorHeight = height - 8;
|
||||||
|
const doorX = x + 4;
|
||||||
|
const doorY = y + 4;
|
||||||
|
const doorGap = doorWidth * doorProgress; // 两扇门之间的间隙
|
||||||
|
|
||||||
|
// 保持金属质感,不根据运动状态改变门的颜色
|
||||||
|
const doorColor1 = '#94a3b8'; // 浅金属蓝灰
|
||||||
|
const doorColor2 = '#64748b'; // 中金属蓝灰
|
||||||
|
const doorColor3 = '#475569'; // 深金属蓝灰
|
||||||
|
const doorColor4 = '#334155'; // 最深金属蓝灰
|
||||||
|
|
||||||
|
// 绘制左门 - 金属门质感(无门把手)
|
||||||
|
if (doorWidth - doorGap / 2 > 0) {
|
||||||
|
// 门主体渐变
|
||||||
|
const doorGradient = ctx.createLinearGradient(doorX, doorY, doorX + doorWidth - doorGap / 2, doorY + doorHeight);
|
||||||
|
doorGradient.addColorStop(0, doorColor1);
|
||||||
|
doorGradient.addColorStop(0.3, doorColor2);
|
||||||
|
doorGradient.addColorStop(0.7, doorColor3);
|
||||||
|
doorGradient.addColorStop(1, doorColor4);
|
||||||
|
ctx.fillStyle = doorGradient;
|
||||||
|
ctx.fillRect(doorX, doorY, doorWidth - doorGap / 2, doorHeight);
|
||||||
|
|
||||||
|
// 门边缘高光
|
||||||
|
ctx.strokeStyle = 'rgba(203, 213, 225, 0.6)';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.strokeRect(doorX + 0.5, doorY + 0.5, doorWidth - doorGap / 2 - 1, doorHeight - 1);
|
||||||
|
|
||||||
|
// 如果在运动中,添加动态线条效果
|
||||||
|
if (direction === 2 || direction === 3) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.strokeStyle = direction === 2 ? 'rgba(16, 185, 129, 0.4)' : 'rgba(239, 68, 68, 0.4)';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.setLineDash([3, 3]);
|
||||||
|
const lineOffset = (time % 1000) / 1000 * 6;
|
||||||
|
ctx.lineDashOffset = direction === 2 ? -lineOffset : lineOffset;
|
||||||
|
|
||||||
|
// 绘制动态线条
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
const lineY = doorY + doorHeight * (0.3 + i * 0.2);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(doorX + 5, lineY);
|
||||||
|
ctx.lineTo(doorX + doorWidth - doorGap / 2 - 5, lineY);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制右门 - 金属门质感(无门把手)
|
||||||
|
if (doorWidth - doorGap / 2 > 0) {
|
||||||
|
// 门主体渐变
|
||||||
|
const doorGradient = ctx.createLinearGradient(doorX + doorWidth + doorGap / 2, doorY, doorX + doorWidth * 2 + doorGap / 2, doorY + doorHeight);
|
||||||
|
doorGradient.addColorStop(0, doorColor1);
|
||||||
|
doorGradient.addColorStop(0.3, doorColor2);
|
||||||
|
doorGradient.addColorStop(0.7, doorColor3);
|
||||||
|
doorGradient.addColorStop(1, doorColor4);
|
||||||
|
ctx.fillStyle = doorGradient;
|
||||||
|
ctx.fillRect(doorX + doorWidth + doorGap / 2, doorY, doorWidth - doorGap / 2, doorHeight);
|
||||||
|
|
||||||
|
// 门边缘高光
|
||||||
|
ctx.strokeStyle = 'rgba(203, 213, 225, 0.6)';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.strokeRect(doorX + doorWidth + doorGap / 2 + 0.5, doorY + 0.5, doorWidth - doorGap / 2 - 1, doorHeight - 1);
|
||||||
|
|
||||||
|
// 如果在运动中,添加动态线条效果
|
||||||
|
if (direction === 2 || direction === 3) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.strokeStyle = direction === 2 ? 'rgba(16, 185, 129, 0.4)' : 'rgba(239, 68, 68, 0.4)';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.setLineDash([3, 3]);
|
||||||
|
const lineOffset = (time % 1000) / 1000 * 6;
|
||||||
|
ctx.lineDashOffset = direction === 2 ? -lineOffset : lineOffset;
|
||||||
|
|
||||||
|
// 绘制动态线条
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
const lineY = doorY + doorHeight * (0.3 + i * 0.2);
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(doorX + doorWidth + doorGap / 2 + 5, lineY);
|
||||||
|
ctx.lineTo(doorX + doorWidth * 2 - 5, lineY);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制电梯顶部指示器 - 基于电梯宽度自适应,增加距离避免被遮挡
|
||||||
|
const indicatorWidth = width * 0.6; // 指示器宽度为电梯宽度的60%
|
||||||
|
const indicatorHeight = Math.max(6, width * 0.12); // 指示器高度为电梯宽度的12%,最小6px
|
||||||
|
const indicatorY = y - Math.max(10, width * 0.25); // 增加距离:电梯宽度的25%,最小10px
|
||||||
|
|
||||||
|
// 顶部指示器背景 - 金属质感
|
||||||
|
const indicatorGradient = ctx.createLinearGradient(x + width/2 - indicatorWidth/2, indicatorY, x + width/2 + indicatorWidth/2, indicatorY + indicatorHeight);
|
||||||
|
indicatorGradient.addColorStop(0, '#6b7280');
|
||||||
|
indicatorGradient.addColorStop(0.5, '#4b5563');
|
||||||
|
indicatorGradient.addColorStop(1, '#374151');
|
||||||
|
ctx.fillStyle = indicatorGradient;
|
||||||
|
ctx.fillRect(x + width/2 - indicatorWidth/2, indicatorY, indicatorWidth, indicatorHeight);
|
||||||
|
|
||||||
|
// 根据方向在顶部指示器内显示状态,使用更大的箭头
|
||||||
|
if (direction === 2) {
|
||||||
|
// 向上状态 - 绿色LED效果
|
||||||
|
// 绘制发光背景
|
||||||
|
const glowGradient = ctx.createRadialGradient(cx, indicatorY + indicatorHeight/2, 0, cx, indicatorY + indicatorHeight/2, indicatorHeight * 1.5);
|
||||||
|
glowGradient.addColorStop(0, 'rgba(16, 185, 129, 0.4)');
|
||||||
|
glowGradient.addColorStop(1, 'rgba(16, 185, 129, 0)');
|
||||||
|
ctx.fillStyle = glowGradient;
|
||||||
|
ctx.fillRect(x + width/2 - indicatorWidth/2 - 3, indicatorY - 3, indicatorWidth + 6, indicatorHeight + 6);
|
||||||
|
|
||||||
|
// 绘制向上箭头 - 更大更明显
|
||||||
|
ctx.fillStyle = '#10b981';
|
||||||
|
ctx.shadowColor = '#10b981';
|
||||||
|
ctx.shadowBlur = 8;
|
||||||
|
|
||||||
|
// 使用更大的箭头,占据整个指示器高度
|
||||||
|
const arrowSize = Math.min(indicatorWidth * 0.4, indicatorHeight * 0.9);
|
||||||
|
const arrowTop = indicatorY + indicatorHeight * 0.1;
|
||||||
|
const arrowBottom = indicatorY + indicatorHeight * 0.9;
|
||||||
|
|
||||||
|
// 主箭头 - 加粗版本
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(cx, arrowTop);
|
||||||
|
ctx.lineTo(cx - arrowSize, arrowBottom);
|
||||||
|
ctx.lineTo(cx - arrowSize * 0.4, arrowBottom - arrowSize * 0.2);
|
||||||
|
ctx.lineTo(cx, arrowBottom - arrowSize * 0.3);
|
||||||
|
ctx.lineTo(cx + arrowSize * 0.4, arrowBottom - arrowSize * 0.2);
|
||||||
|
ctx.lineTo(cx + arrowSize, arrowBottom);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.shadowBlur = 0;
|
||||||
|
} else if (direction === 3) {
|
||||||
|
// 向下状态 - 红色LED效果
|
||||||
|
// 绘制发光背景
|
||||||
|
const glowGradient = ctx.createRadialGradient(cx, indicatorY + indicatorHeight/2, 0, cx, indicatorY + indicatorHeight/2, indicatorHeight * 1.5);
|
||||||
|
glowGradient.addColorStop(0, 'rgba(239, 68, 68, 0.4)');
|
||||||
|
glowGradient.addColorStop(1, 'rgba(239, 68, 68, 0)');
|
||||||
|
ctx.fillStyle = glowGradient;
|
||||||
|
ctx.fillRect(x + width/2 - indicatorWidth/2 - 3, indicatorY - 3, indicatorWidth + 6, indicatorHeight + 6);
|
||||||
|
|
||||||
|
// 绘制向下箭头 - 更大更明显
|
||||||
|
ctx.fillStyle = '#ef4444';
|
||||||
|
ctx.shadowColor = '#ef4444';
|
||||||
|
ctx.shadowBlur = 8;
|
||||||
|
|
||||||
|
// 使用更大的箭头,占据整个指示器高度
|
||||||
|
const arrowSize = Math.min(indicatorWidth * 0.4, indicatorHeight * 0.9);
|
||||||
|
const arrowTop = indicatorY + indicatorHeight * 0.1;
|
||||||
|
const arrowBottom = indicatorY + indicatorHeight * 0.9;
|
||||||
|
|
||||||
|
// 主箭头 - 加粗版本
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(cx, arrowBottom);
|
||||||
|
ctx.lineTo(cx - arrowSize, arrowTop);
|
||||||
|
ctx.lineTo(cx - arrowSize * 0.4, arrowTop + arrowSize * 0.2);
|
||||||
|
ctx.lineTo(cx, arrowTop + arrowSize * 0.3);
|
||||||
|
ctx.lineTo(cx + arrowSize * 0.4, arrowTop + arrowSize * 0.2);
|
||||||
|
ctx.lineTo(cx + arrowSize, arrowTop);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.shadowBlur = 0;
|
||||||
|
} else if (direction === 1) {
|
||||||
|
// 停止状态 - 黄色LED效果
|
||||||
|
// 绘制发光背景
|
||||||
|
const glowGradient = ctx.createRadialGradient(cx, indicatorY + indicatorHeight/2, 0, cx, indicatorY + indicatorHeight/2, indicatorHeight);
|
||||||
|
glowGradient.addColorStop(0, 'rgba(245, 158, 11, 0.3)');
|
||||||
|
glowGradient.addColorStop(1, 'rgba(245, 158, 11, 0)');
|
||||||
|
ctx.fillStyle = glowGradient;
|
||||||
|
ctx.fillRect(x + width/2 - indicatorWidth/2 - 2, indicatorY - 2, indicatorWidth + 4, indicatorHeight + 4);
|
||||||
|
|
||||||
|
// 绘制停止标志
|
||||||
|
ctx.fillStyle = '#f59e0b';
|
||||||
|
ctx.shadowColor = '#f59e0b';
|
||||||
|
ctx.shadowBlur = 6;
|
||||||
|
const stopSize = Math.min(indicatorHeight * 0.6, indicatorWidth * 0.18);
|
||||||
|
|
||||||
|
// 绘制矩形停止标志
|
||||||
|
ctx.fillRect(cx - stopSize/2, indicatorY + (indicatorHeight - stopSize)/2, stopSize, stopSize);
|
||||||
|
|
||||||
|
// 添加脉冲效果
|
||||||
|
const pulsePhase = (time % 2000) / 2000 * Math.PI * 2;
|
||||||
|
const pulseAlpha = 0.3 + 0.2 * Math.sin(pulsePhase);
|
||||||
|
ctx.fillStyle = `rgba(245, 158, 11, ${pulseAlpha})`;
|
||||||
|
ctx.fillRect(cx - stopSize/2 - 2, indicatorY + (indicatorHeight - stopSize)/2 - 2, stopSize + 4, stopSize + 4);
|
||||||
|
|
||||||
|
ctx.shadowBlur = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加电梯边框 - 金属边缘效果
|
||||||
|
ctx.strokeStyle = '#1f2937';
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.strokeRect(x, y, width, height);
|
||||||
|
|
||||||
|
// 添加金属边缘高光
|
||||||
|
ctx.strokeStyle = 'rgba(156, 163, 175, 0.4)';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.strokeRect(x + 1, y + 1, width - 2, height - 2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 绘制电梯点的极简状态指示 - 设计理念:
|
* 绘制电梯点的极简状态指示 - 设计理念:
|
||||||
* 1. 简约至上:仅使用矩形边框和颜色传达状态,无文字说明
|
* 1. 简约至上:仅使用矩形边框和颜色传达状态,无文字说明
|
||||||
* 2. 图片优先:确保48*60电梯图片完全可见,边框不覆盖主体
|
* 2. Canvas绘制电梯图标:使用48*60电梯图标,边框不覆盖主体
|
||||||
* 3. 响应式设计:所有尺寸基于pen元素宽高动态计算,完美适配画布缩放
|
* 3. 响应式设计:所有尺寸基于pen元素宽高动态计算,完美适配画布缩放
|
||||||
* 4. 直观色彩:
|
* 4. 直观色彩:
|
||||||
* - 红色虚线:离线状态
|
* - 红色虚线:离线状态
|
||||||
@ -66,7 +321,7 @@ function drawDisconnectedIcon(ctx: CanvasRenderingContext2D, cx: number, cy: num
|
|||||||
* - 绿色箭头:上行/下行方向指示
|
* - 绿色箭头:上行/下行方向指示
|
||||||
* - 金色:停止
|
* - 金色:停止
|
||||||
* - 灰色:未知状态
|
* - 灰色:未知状态
|
||||||
* 5. 静态箭头:上下行时在边框右侧显示静态箭头,简洁清晰
|
* 5. 动态箭头:上下行时在边框右侧显示动态箭头,简洁清晰
|
||||||
*
|
*
|
||||||
* 尺寸计算规则:
|
* 尺寸计算规则:
|
||||||
* - 边框距离:最小4px,否则按pen较小边的15%计算
|
* - 边框距离:最小4px,否则按pen较小边的15%计算
|
||||||
@ -163,131 +418,29 @@ function drawElevatorMinimal(
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 辅助函数:在边框右侧绘制动态方向箭头(根据时间动画)
|
// 箭头绘制函数已移除,因为箭头现在集成在电梯图标内部
|
||||||
const drawDirectionSide = (direction: 'up' | 'down', color: string, time: number) => {
|
// 方向指示通过电梯顶部的LED指示器显示
|
||||||
ctx.save();
|
|
||||||
ctx.fillStyle = color;
|
|
||||||
ctx.strokeStyle = color;
|
|
||||||
ctx.globalAlpha = 0.8;
|
|
||||||
|
|
||||||
// 箭头大小基于pen尺寸动态调整,分别考虑宽度和高度
|
|
||||||
const arrowSize = Math.max(5, Math.min(w, h) * 0.20); // 使用较小的边作为基准,最小5px,否则按20%比例
|
|
||||||
const sideMargin = Math.max(5, Math.min(w, h) * 0.20); // 距离右侧边框的距离,增加间距,使用较小的边作为基准
|
|
||||||
ctx.lineWidth = Math.max(2, Math.min(w, h) * 0.04); // 箭头线条宽度,使用较小的边作为基准
|
|
||||||
|
|
||||||
// 箭头位置:在矩形右侧垂直居中
|
|
||||||
const arrowX = rectX + rectW + sideMargin;
|
|
||||||
const centerY = y + h / 2; // 垂直居中
|
|
||||||
// 动画偏移:当电梯上下移动时,箭头沿方向移动
|
|
||||||
let offset = 0;
|
|
||||||
if (elevatorDirection === 2 || elevatorDirection === 3) {
|
|
||||||
// 周期1000ms,振幅为箭头大小的50%
|
|
||||||
const amplitude = arrowSize * 0.5;
|
|
||||||
const period = 1000; // 毫秒
|
|
||||||
const phase = (time % period) / period;
|
|
||||||
// 正弦波产生平滑往复运动,方向决定符号
|
|
||||||
const sign = direction === 'up' ? -1 : 1;
|
|
||||||
offset = Math.sin(phase * 2 * Math.PI) * amplitude * sign;
|
|
||||||
}
|
|
||||||
const animatedCenterY = centerY + offset;
|
|
||||||
|
|
||||||
if (direction === 'up') {
|
|
||||||
// 向上箭头 - 在右侧绘制
|
|
||||||
ctx.beginPath();
|
|
||||||
// 箭头主体(竖线)
|
|
||||||
ctx.moveTo(arrowX, animatedCenterY + arrowSize);
|
|
||||||
ctx.lineTo(arrowX, animatedCenterY - arrowSize);
|
|
||||||
// 箭头尖端(三角形)
|
|
||||||
ctx.lineTo(arrowX - arrowSize * 0.6, animatedCenterY - arrowSize * 0.4);
|
|
||||||
ctx.moveTo(arrowX, animatedCenterY - arrowSize);
|
|
||||||
ctx.lineTo(arrowX + arrowSize * 0.6, animatedCenterY - arrowSize * 0.4);
|
|
||||||
ctx.stroke();
|
|
||||||
|
|
||||||
// 填充箭头头部
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(arrowX, animatedCenterY - arrowSize);
|
|
||||||
ctx.lineTo(arrowX - arrowSize * 0.5, animatedCenterY - arrowSize * 0.7);
|
|
||||||
ctx.lineTo(arrowX + arrowSize * 0.5, animatedCenterY - arrowSize * 0.7);
|
|
||||||
ctx.closePath();
|
|
||||||
ctx.fill();
|
|
||||||
} else {
|
|
||||||
// 向下箭头 - 在右侧绘制
|
|
||||||
ctx.beginPath();
|
|
||||||
// 箭头主体(竖线)
|
|
||||||
ctx.moveTo(arrowX, animatedCenterY - arrowSize);
|
|
||||||
ctx.lineTo(arrowX, animatedCenterY + arrowSize);
|
|
||||||
// 箭头尖端(三角形)
|
|
||||||
ctx.lineTo(arrowX - arrowSize * 0.6, animatedCenterY + arrowSize * 0.4);
|
|
||||||
ctx.moveTo(arrowX, animatedCenterY + arrowSize);
|
|
||||||
ctx.lineTo(arrowX + arrowSize * 0.6, animatedCenterY + arrowSize * 0.4);
|
|
||||||
ctx.stroke();
|
|
||||||
|
|
||||||
// 填充箭头头部
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(arrowX, animatedCenterY + arrowSize);
|
|
||||||
ctx.lineTo(arrowX - arrowSize * 0.5, animatedCenterY + arrowSize * 0.7);
|
|
||||||
ctx.lineTo(arrowX + arrowSize * 0.5, animatedCenterY + arrowSize * 0.7);
|
|
||||||
ctx.closePath();
|
|
||||||
ctx.fill();
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.restore();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 状态渲染逻辑 - 根据需求优化配色方案
|
// 绘制电梯图标(包含内部的方向指示器)
|
||||||
|
drawElevatorIcon(
|
||||||
|
ctx,
|
||||||
|
x + w / 2,
|
||||||
|
y + h / 2,
|
||||||
|
Math.min(48, w * 0.8), // 根据pen大小调整电梯图标宽度,最大48像素
|
||||||
|
Math.min(60, h * 0.8), // 根据pen大小调整电梯图标高度,最大60像素
|
||||||
|
elevatorFrontDoorStatus,
|
||||||
|
time,
|
||||||
|
elevatorDirection
|
||||||
|
);
|
||||||
|
|
||||||
|
// 状态渲染逻辑 - 只有断连状态才显示边框
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
// 离线状态 - 红色虚线(静态,不带动画)
|
// 离线状态 - 红色虚线(静态,不带动画)
|
||||||
drawMinimalFrame('#FF4757', 0.8, true, time);
|
drawMinimalFrame('#FF4757', 0.8, true, time);
|
||||||
} else {
|
|
||||||
// 在线状态根据具体状态渲染
|
|
||||||
switch (elevatorFrontDoorStatus) {
|
|
||||||
case 2: { // 正在开关门 - 蓝色虚线边框 + 绿色箭头
|
|
||||||
// 蓝色虚线边框表示操作中(带动画)
|
|
||||||
drawMinimalFrame('#69c6f5', 0.8, true, time);
|
|
||||||
if (elevatorDirection === 2) { // 向上
|
|
||||||
drawDirectionSide('up', '#00D26A', time); // 绿色箭头
|
|
||||||
} else if (elevatorDirection === 3) { // 向下
|
|
||||||
drawDirectionSide('down', '#00D26A', time); // 绿色箭头
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 3: { // 门已开 - 实线绿色边框 + 绿色箭头
|
|
||||||
// 实线绿色边框表示可通行状态
|
|
||||||
drawMinimalFrame('#00D26A', 0.8, false, time);
|
|
||||||
if (elevatorDirection === 2) { // 向上
|
|
||||||
drawDirectionSide('up', '#00D26A', time); // 绿色箭头
|
|
||||||
} else if (elevatorDirection === 3) { // 向下
|
|
||||||
drawDirectionSide('down', '#00D26A', time); // 绿色箭头
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 1: { // 门已关 - 根据方向显示
|
|
||||||
if (elevatorDirection === 2) { // 向上
|
|
||||||
// 蓝色边框 + 绿色向上箭头
|
|
||||||
drawMinimalFrame('#69c6f5', 0.8, false, time);
|
|
||||||
drawDirectionSide('up', '#00D26A', time); // 绿色箭头
|
|
||||||
} else if (elevatorDirection === 3) { // 向下
|
|
||||||
// 蓝色边框 + 绿色向下箭头
|
|
||||||
drawMinimalFrame('#69c6f5', 0.8, false, time);
|
|
||||||
drawDirectionSide('down', '#00D26A', time); // 绿色箭头
|
|
||||||
} else { // 停止
|
|
||||||
// 金色静态边框 - 中性状态
|
|
||||||
drawMinimalFrame('#FFB700', 0.7, false, time);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: { // 未知状态
|
|
||||||
// 灰色静态边框
|
|
||||||
drawMinimalFrame('#8B8B8B', 0.5, false, time);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// 其他状态(在线)不需要额外的边框和箭头,所有信息都集成在电梯图标内部
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -524,9 +677,9 @@ export function drawPoint(ctx: CanvasRenderingContext2D, pen: MapPen): void {
|
|||||||
ctx.strokeStyle = largeTypeStrokeColor || largeGeneralStrokeColor || largeThemeStrokeColor || '';
|
ctx.strokeStyle = largeTypeStrokeColor || largeGeneralStrokeColor || largeThemeStrokeColor || '';
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
// 电梯点:使用极简状态渲染
|
// 电梯点:使用Canvas绘制的电梯图标
|
||||||
if (type === MapPointType.电梯点) {
|
if (type === MapPointType.电梯点) {
|
||||||
// 直接传入包含后端字段的 pen.point 数据
|
// 绘制Canvas电梯图标和状态
|
||||||
if (pen.point) {
|
if (pen.point) {
|
||||||
drawElevatorMinimal(ctx, pen, pen.point, currentTime);
|
drawElevatorMinimal(ctx, pen, pen.point, currentTime);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -111,7 +111,8 @@ export class PointManager {
|
|||||||
|
|
||||||
private mapPointImage(type: MapPointType): Required<Pick<MapPen, 'image' | 'canvasLayer'>> {
|
private mapPointImage(type: MapPointType): Required<Pick<MapPen, 'image' | 'canvasLayer'>> {
|
||||||
const theme = this.editor.data().theme;
|
const theme = this.editor.data().theme;
|
||||||
const image = type < 10 ? '' : `${import.meta.env.BASE_URL}/point/${type}-${theme}.png`;
|
// 电梯点(type=11)不加载默认图标,使用Canvas绘制
|
||||||
|
const image = type < 10 || type === MapPointType.电梯点 ? '' : `${import.meta.env.BASE_URL}/point/${type}-${theme}.png`;
|
||||||
return { image, canvasLayer: CanvasLayer.CanvasMain };
|
return { image, canvasLayer: CanvasLayer.CanvasMain };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user