Draw Lines on HTML Canvas Underlying Web Content

  Kiến thức lập trình

I’m working on a project to draw lines on an HTML canvas beneath webpage’s content. My goal is to achieve a result similar to the screenshot attached. Here’s what I’ve done so far:

let container = document.querySelector(".container");
let canvas = document.querySelector("canvas");

canvas.width = container.offsetWidth;
canvas.height = container.offsetHeight;

let ctx = canvas.getContext("2d");

let photo = document.querySelector(".photo");
let levels = document.querySelectorAll(".levels div");
let colors = getComputedStyle(document.documentElement);

levels.forEach((level, index) => {
  index++;
  ctx.beginPath();
  ctx.strokeStyle = colors.getPropertyValue(`--level-${index}`);
  ctx.moveTo(photo.offsetWidth + index * 10, photo.offsetTop + level.offsetTop - level.offsetHeight / 2);
  ctx.lineTo(photo.offsetWidth, photo.offsetTop + level.offsetTop - level.offsetHeight / 2);
  ctx.stroke();
});

let person = document.querySelector(".person");
let boxes = document.querySelectorAll(".box");
let total = boxes.length;
boxes.forEach((box, index) => {
  let dot = box.querySelector(".dot");
  index++;
  ctx.beginPath();
  ctx.strokeStyle = colors.getPropertyValue(`--level-${index}`);
  ctx.moveTo(person.offsetWidth + dot.offsetLeft + dot.offsetWidth, box.offsetTop - dot.offsetTop + dot.offsetHeight);
  ctx.lineTo(
    person.offsetWidth + dot.offsetLeft + dot.offsetWidth / 2 - total * 10,
    box.offsetTop - dot.offsetTop + dot.offsetHeight
  );
  ctx.stroke();
  total--;
});
:root {
  --level-1: #39a3aa;
  --level-2: #32a993;
  --level-3: #5cb793;
  --level-4: #dbb00c;
  --level-5: #d8750e;
  --level-6: #d4181c;
  --level-7: #b1111d;
}
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  font-family: "Roboto", sans-serif;
  font-weight: 400;
  font-style: normal;
  color: rgba(0, 0, 0, 0.87);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
.container {
  width: 1080px;
  height: 100%;
  margin: 0 auto;
  padding: 40px 0;
  display: flex;
  position: relative;
}
.person {
  flex-basis: 42%;
  display: flex;
  align-items: center;
}
.person .photo {
  width: 280px;
  height: 280px;
  position: relative;
}
.person .photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.person .photo .levels {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  position: absolute;
  top: 0;
}
.person .photo .levels [class^="level"] {
  flex: 1;
  opacity: 0.8;
}
.questions {
  flex-basis: 58%;
}
.questions .box {
  border: 1px solid;
  padding: 15px 10px;
  position: relative;
  margin-bottom: 24px;
}
.questions .box .dot {
  width: 10px;
  height: 10px;
  border-radius: 100%;
  position: absolute;
  top: 22px;
  left: -24px;
}
.questions .box .arrow {
  border-style: solid;
  border-width: 0 1px 1px 0;
  transform: rotate(45deg);
  padding: 12px;
  position: absolute;
  left: calc(50% - 6px);
  top: calc(100% - 12px);
  background-color: #fff;
}
.questions .box .question {
  margin-bottom: 5px;
}
.questions .box .question span {
  font-weight: 600;
}
.questions .box .answer input {
  padding: 6px 0;
  border: 0;
  outline: 0;
  width: 100%;
  font-family: inherit;
  font-size: inherit;
  position: relative;
  z-index: 1;
  color: inherit;
}
.questions .box .answer input::placeholder {
  color: #acacac;
}
canvas {
  position: absolute;
  z-index: -1;
}
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,400;0,600;&display=swap" rel="stylesheet" />

<div id="app">
  <div class="container">
    <div class="person">
      <div class="photo">
        <img src="headshot.jpeg" alt="" />
        <div class="levels">
          <div class="level-1" style="background-color: var(--level-1)"></div>
          <div class="level-2" style="background-color: var(--level-2)"></div>
          <div class="level-3" style="background-color: var(--level-3)"></div>
          <div class="level-4" style="background-color: var(--level-4)"></div>
          <div class="level-5" style="background-color: var(--level-5)"></div>
          <div class="level-6" style="background-color: var(--level-6)"></div>
          <div class="level-7" style="background-color: var(--level-7)"></div>
        </div>
      </div>
    </div>
    <div class="questions">
      <div class="box question-1" style="border-color: var(--level-1)">
        <div class="dot" style="background-color: var(--level-1)"></div>
        <p class="question">
          <span style="color: var(--level-1)">Level 1: </span>Lorem ipsum dolor sit amet, consectetur adipiscing elit?
        </p>
        <div class="answer">
          <input type="text" placeholder="Type your answer here and press Enter." />
        </div>
        <div class="arrow" style="border-color: var(--level-1)"></div>
      </div>

      <div class="box question-2" style="border-color: var(--level-2)">
        <div class="dot" style="background-color: var(--level-2)"></div>
        <p class="question">
          <span style="color: var(--level-2)">Level 2: </span>Lorem ipsum dolor sit amet, consectetur adipiscing elit?
        </p>
        <div class="answer">
          <input type="text" placeholder="Type your answer here and press Enter." />
        </div>
        <div class="arrow" style="border-color: var(--level-2)"></div>
      </div>

      <div class="box question-3" style="border-color: var(--level-3)">
        <div class="dot" style="background-color: var(--level-3)"></div>
        <p class="question">
          <span style="color: var(--level-3)">Level 3: </span>Lorem ipsum dolor sit amet, consectetur adipiscing elit?
        </p>
        <div class="answer">
          <input type="text" placeholder="Type your answer here and press Enter." />
        </div>
        <div class="arrow" style="border-color: var(--level-3)"></div>
      </div>

      <div class="box question-4" style="border-color: var(--level-4)">
        <div class="dot" style="background-color: var(--level-4)"></div>
        <p class="question">
          <span style="color: var(--level-4)">Level 4: </span>Lorem ipsum dolor sit amet, consectetur adipiscing elit?
        </p>
        <div class="answer">
          <input type="text" placeholder="Type your answer here and press Enter." />
        </div>
        <div class="arrow" style="border-color: var(--level-4)"></div>
      </div>

      <div class="box question-5" style="border-color: var(--level-5)">
        <div class="dot" style="background-color: var(--level-5)"></div>
        <p class="question">
          <span style="color: var(--level-5)">Level 5: </span>Lorem ipsum dolor sit amet, consectetur adipiscing elit?
        </p>
        <div class="answer">
          <input type="text" placeholder="Type your answer here and press Enter." />
        </div>
        <div class="arrow" style="border-color: var(--level-5)"></div>
      </div>

      <div class="box question-6" style="border-color: var(--level-6)">
        <div class="dot" style="background-color: var(--level-6)"></div>
        <p class="question">
          <span style="color: var(--level-6)">Level 6: </span>Lorem ipsum dolor sit amet, consectetur adipiscing elit?
        </p>
        <div class="answer">
          <input type="text" placeholder="Type your answer here and press Enter." />
        </div>
        <div class="arrow" style="border-color: var(--level-6)"></div>
      </div>

      <div class="box question-7" style="border-color: var(--level-7)">
        <div class="dot" style="background-color: var(--level-7)"></div>
        <p class="question">
          <span style="color: var(--level-7)">Level 7: </span>Lorem ipsum dolor sit amet, consectetur adipiscing elit?
        </p>
        <div class="answer">
          <input type="text" placeholder="Type your answer here and press Enter." />
        </div>
        <div class="arrow" style="border-color: var(--level-7)"></div>
      </div>
    </div>
    <canvas></canvas>
  </div>
</div>

But, I’m having trouble getting the lines to look right. Can someone help me make my code better so it does what I want? Also, if there’s a simpler way to do this than using a canvas under the webpage, I’m open to suggestions.

desired outcome

1

LEAVE A COMMENT