基于需要画一个线路图的需求,由于本人只会一些古老的JS,因此考虑使用表格实现这个功能。
首先动态绘制一个固定行和列的表格,然后给每个单元格赋予一个ID,增加一个点击的监听事件,当收到点击事件时,把当前背景样式改为红色,并进行连线。

首先看图1

可以看到,绘制的表格已经均匀绘制满了屏幕的一块固定区域,然后点击某个单元格,会高亮该点,并且绘图。
但是这样很丑,正常我们会赋予一个底图,把表格的边缘隐藏,修改样式后,如图2

参考代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>高亮点击单元格并画线</title>
<style>
body, html {
height: 100%;
margin: 0;
overflow: hidden;
}
.table-container {
height: 90%;
width: 70%;
margin: auto;
overflow: hidden;
position: relative;
}
table {
border-collapse: collapse;
width: 100%;
height: 100%;
table-layout: fixed;
position: absolute;
border: none;
background-color: transparent;
/* 下面两行,设置背景图片并让它平铺,拉伸图片覆盖整个表格*/
background: url('demo.jpg');
background-size: cover;
}
td {
/* border: 1px solid #ddd;*/
/* 下面两行的修改,为实现隐藏单元格的效果*/
border: none;
background-color: transparent;
text-align: center;
vertical-align: middle;
overflow: hidden;
white-space: nowrap;
}
.trajectory-line {
position: absolute;
background-color: blue;
z-index: 1;
height: 2px;
}
@media screen and (orientation: landscape) {
td {
height: calc(100% / 200);
width: calc(100% / 200);
}
}
@media screen and (orientation: portrait) {
td {
height: calc(80vh / 200);
width: calc(70vw / 200);
}
}
</style>
</head>
<body>
<div>
<table>
<script>
const table = document.querySelector("table");
const tableContainer = document.querySelector(".table-container");
let highlightedCells = [];
let trajectoryLines = [];
// 画一个固定的单元格
for (let i = 0; i < 200; i++) {
const row = document.createElement('tr');
for (let j = 0; j < 280; j++) {
const cell = document.createElement('td');
cell.id = `${i}_${j}`;
cell.addEventListener('click', function() {
const currentColor = window.getComputedStyle(this).backgroundColor;
const isRed = currentColor.toLowerCase() === 'rgb(255, 0, 0)'
|| currentColor.toLowerCase() === 'red';
if (isRed) {
this.style.backgroundColor = '';
removeHighlight(this);
} else {
this.style.backgroundColor = 'red';
highlightedCells.push(this);
if (highlightedCells.length > 1) {
drawTrajectory();
}
}
});
row.appendChild(cell);
}
table.appendChild(row);
}
function removeHighlight(cell) {
const index = highlightedCells.indexOf(cell);
if (index > -1) {
highlightedCells.splice(index, 1);
}
trajectoryLines.forEach(line => line.remove());
trajectoryLines = [];
drawTrajectory();
}
// 把高亮的单元格,画线
function drawTrajectory() {
trajectoryLines.forEach(line => line.remove());
trajectoryLines = [];
// 获取容器相对视口的位置(含滚动偏移)
const containerRect = tableContainer.getBoundingClientRect();
highlightedCells.forEach((cell, index) => {
if (index === highlightedCells.length - 1) return;
const nextCell = highlightedCells[index + 1];
const cellRect = cell.getBoundingClientRect();
const nextRect = nextCell.getBoundingClientRect();
// 计算单元格中心点(相对容器)
const startX = cellRect.left + cellRect.width/2 - containerRect.left;
const startY = cellRect.top + cellRect.height/2 - containerRect.top;
const endX = nextRect.left + nextRect.width/2 - containerRect.left;
const endY = nextRect.top + nextRect.height/2 - containerRect.top;
// 计算向量差值(关键修正点)
const deltaX = endX - startX;
const deltaY = endY - startY;
// 创建轨迹线元素
const line = document.createElement('div');
line.className = 'trajectory-line';
// 关键属性设置(修正旋转中心)
line.style.position = 'absolute';
line.style.transformOrigin = 'left top'; // 以起点为旋转中心
line.style.left = `${startX}px`;
line.style.top = `${startY}px`;
// 计算角度和长度(使用向量差值)
const length = Math.sqrt(deltaX*deltaX + deltaY*deltaY);
const angle = Math.atan2(deltaY, deltaX) * 180 / Math.PI;
line.style.width = `${length}px`;
line.style.transform = `rotate(${angle}deg)`;
line.style.height = '2px';
line.style.backgroundColor = 'blue';
line.style.zIndex = 1;
tableContainer.appendChild(line);
trajectoryLines.push(line);
});
}
function highlightInitialCells() {
const cellsToHighlight = [
{row: 9, column: 1},
{row: 10, column: 150},
{row: 20, column: 50},
{row: 80, column: 200},
{row: 80, column: 150},
{row: 120, column: 30}
];
cellsToHighlight.forEach(cell => {
const cellId = `${cell.row}_${cell.column}`;
const element = document.getElementById(cellId);
if (element) {
element.style.backgroundColor = 'red';
highlightedCells.push(element);
}
});
if (highlightedCells.length > 1) {
drawTrajectory();
}
}
window.onload = function() {
highlightInitialCells();
};
</script>
</table>
</div>
</body>
</html>具体是显示图片还是单元格,可以在table和td的样式处就行调整。