
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用canvas画连接线(直角边)</title>
<style>
#app {
margin: 50px 80px;
}
.row {
position: relative;
display: flex;
justify-content: space-between;
}
.row .col {
z-index: 2;
width: 140px;
}
.col .item {
width: 140px;
height: 80px;
margin-right: 30px;
border: 1px solid #ccc;
margin-bottom: 30px;
background-color: pink;
}
canvas {
border: 1px solid #d3d3d3;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
}
</style>
</head>
<body>
<div id="app">
<div class="row" id="dots-container">
<div class="col">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
</div>
<div class="col">
</div>
<div class="col">
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
</div>
<div class="col">
<div class="item">8</div>
</div>
<div class="col">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="col">
</div>
<div class="col">
</div>
<canvas id="bg-line"></canvas>
</div>
</div>
<script>
const drawLine = (eleFrom, eleTo, eleParent, ctx, {
col2colWidth
}) => {
const rectFrom = eleFrom.getBoundingClientRect();
const rectTo = eleTo.getBoundingClientRect();
const rectParent = eleParent.getBoundingClientRect();
const relativeCenterFrom = {
x: rectFrom.x - rectParent.x + rectFrom.width / 2,
y: rectFrom.y - rectParent.y + rectFrom.height / 2
};
const relativeCenterTo = {
x: rectTo.x - rectParent.x + rectTo.width / 2,
y: rectTo.y - rectParent.y + rectTo.height / 2
};
if (relativeCenterFrom.x === relativeCenterTo.x || relativeCenterFrom.y === relativeCenterTo.y) {
ctx.moveTo(relativeCenterFrom.x, relativeCenterFrom.y);
ctx.lineTo(relativeCenterTo.x, relativeCenterTo.y);
ctx.stroke();
return;
}
const borderRadius = 20;
const arcFrom = {
x: relativeCenterFrom.x + col2colWidth / 2,
y: relativeCenterFrom.y
};
const arcTo = {
x: relativeCenterFrom.x + col2colWidth / 2,
y: relativeCenterTo.y
};
ctx.moveTo(relativeCenterFrom.x, relativeCenterFrom.y);
ctx.lineTo(arcFrom.x - borderRadius, arcFrom.y);
ctx.arcTo(arcFrom.x, arcFrom.y, arcFrom.x, arcFrom.y - borderRadius, borderRadius);
ctx.lineTo(arcTo.x, arcTo.y + borderRadius);
ctx.arcTo(arcTo.x, arcTo.y, arcTo.x + borderRadius, arcTo.y, borderRadius);
ctx.lineTo(relativeCenterTo.x, relativeCenterTo.y);
ctx.stroke();
}
const connectLines = (itemSelector, colSelector, parentSelector, canvasId, {
lineColor
} = {
lineColor: "#ccc"
}) => {
const canvasEle = document.getElementById(canvasId);
const ctx = canvasEle.getContext("2d");
const items = document.querySelectorAll(itemSelector);
ctx.strokeStyle = lineColor;
ctx.lineWidth = 1;
const cols = document.querySelectorAll(colSelector);
let col2colWidth = 0;
if (cols.length > 1) {
col2colWidth = cols[1].getBoundingClientRect().left - cols[0].getBoundingClientRect().left;
}
for (let index = 0; index < items.length; index++) {
if (index >= items.length - 1) {
break;
}
drawLine(items[index], items[index + 1], document.querySelector(parentSelector), ctx, {
col2colWidth
});
}
}
const initCanvas = (canvasId) => {
const canvasEle = document.getElementById(canvasId);
if (!canvasEle) {
return;
}
const width = canvasEle.clientWidth;
const height = canvasEle.clientHeight;
canvasEle.setAttribute("width", `${width}px`);
canvasEle.setAttribute("height", `${height}px`);
}
initCanvas("bg-line");
connectLines(".item", ".col", ".row", "bg-line", {
lineColor: "blue"
});
</script>
</body>
</html>
总结:
- canvas需要设置width和height属性,不然会有默认宽高,绘制的图形会被放大或压缩;
- canvas绘制线条api:moveTo、lineTo、artTo、stroke;